mod table;
use super::{Result, app, db, mapping};
use crate::schema::mapping::TableToModel;
use crate::schema::{Mapping, Schema, Table, TableId};
use crate::{driver, stmt};
use indexmap::IndexMap;
#[derive(Debug)]
pub struct Builder {
table_name_prefix: Option<String>,
}
struct BuildSchema<'a> {
builder: &'a Builder,
db: &'a driver::Capability,
table_lookup: IndexMap<String, TableId>,
tables: Vec<Table>,
mapping: Mapping,
}
impl Builder {
pub fn new() -> Self {
Self {
table_name_prefix: None,
}
}
pub fn table_name_prefix(&mut self, prefix: &str) -> &mut Self {
self.table_name_prefix = Some(prefix.to_string());
self
}
pub fn build(&self, mut app: app::Schema, db: &driver::Capability) -> Result<Schema> {
let mut builder = BuildSchema {
builder: self,
db,
table_lookup: IndexMap::new(),
tables: vec![],
mapping: Mapping {
models: IndexMap::new(),
},
};
for model in app.models.values_mut() {
model.verify(db)?;
builder.build_model_constraints(model)?;
}
for model in app.models() {
let app::Model::Root(model) = model else {
continue;
};
let table = builder.build_table_stub_for_model(model);
builder.mapping.models.insert(
model.id,
mapping::Model {
id: model.id,
table,
columns: vec![],
fields: vec![], model_to_table: stmt::ExprRecord::default(),
table_to_model: TableToModel::default(),
},
);
}
builder.build_tables_from_models(&app, db)?;
let schema = Schema {
app,
db: db::Schema {
tables: builder.tables,
},
mapping: builder.mapping,
};
schema.verify()?;
Ok(schema)
}
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}
impl BuildSchema<'_> {
fn build_model_constraints(&self, model: &mut app::Model) -> Result<()> {
let fields = match model {
app::Model::Root(root) => &mut root.fields[..],
app::Model::EmbeddedStruct(embedded) => &mut embedded.fields[..],
app::Model::EmbeddedEnum(_) => return Ok(()),
};
for field in fields.iter_mut() {
if let app::FieldTy::Primitive(primitive) = &mut field.ty {
let storage_ty = db::Type::from_app(
&primitive.ty,
primitive.storage_ty.as_ref(),
&self.db.storage_types,
)?;
if let db::Type::VarChar(size) = storage_ty {
field
.constraints
.push(app::Constraint::length_less_than(size));
}
}
}
Ok(())
}
}