use super::model::Model;
use super::render;
use crate::database::introspection::Schema;
use crate::generators::layout::{self, Module};
use crate::generators::naming;
use std::io;
use std::path::Path;
pub use crate::generators::layout::Layout;
const ROOT: &str = "mod.tether";
pub fn write(out: &Path, schema: &Schema, force: bool) -> io::Result<Layout> {
let names = naming::resolve(schema);
let modules: Vec<Module> = schema
.tables
.iter()
.zip(&names)
.map(|(table, names)| {
let model = Model::resolve(table, schema, names);
Module {
name: model.module.clone(),
has_extra_types: false,
files: render::files(&model),
}
})
.collect();
layout::write(out, &modules, ROOT, declarations, declares, force)
}
fn declarations(modules: &[Module]) -> String {
let mut file = String::from(
"// Database models.\n\
//\n\
// Written once by `rustyroad pull`, then yours: add hand-written models here\n\
// alongside the generated ones. A model added to the database later is\n\
// reported by `pull` rather than inserted, so your edits survive.\n\n",
);
for module in modules {
file.push_str(&format!(
"import \"./{}/mod.tether\" as {}\n",
module.name, module.name
));
}
file.push('\n');
for module in modules {
file.push_str(&format!("export {}\n", module.name));
}
file
}
fn declares(contents: &str, name: &str) -> bool {
let path = format!("\"./{name}/mod.tether\"");
contents
.lines()
.any(|line| line.trim_start().starts_with("import") && line.contains(&path))
}