2021-09-03 16:51:22 +08:00

127 lines
5.2 KiB
Rust

use crate::{
Column, ConjunctRelation, Entity, EntityWriter, Error, PrimaryKey, Relation, RelationType,
};
use sea_query::TableStatement;
use std::collections::HashMap;
#[derive(Clone, Debug)]
pub struct EntityTransformer;
impl EntityTransformer {
pub fn transform(table_stmts: Vec<TableStatement>) -> Result<EntityWriter, Error> {
let mut inverse_relations: HashMap<String, Vec<Relation>> = HashMap::new();
let mut conjunct_relations: HashMap<String, Vec<ConjunctRelation>> = HashMap::new();
let mut entities = HashMap::new();
for table_stmt in table_stmts.into_iter() {
let table_create = match table_stmt {
TableStatement::Create(stmt) => stmt,
_ => {
return Err(Error::TransformError(
"TableStatement should be create".into(),
))
}
};
let table_name = match table_create.get_table_name() {
Some(s) => s,
None => {
return Err(Error::TransformError(
"Table name should not be empty".into(),
))
}
};
let columns: Vec<Column> = table_create
.get_columns()
.iter()
.map(|col_def| col_def.into())
.collect();
let relations = table_create
.get_foreign_key_create_stmts()
.iter()
.map(|fk_create_stmt| fk_create_stmt.get_foreign_key())
.map(|tbl_fk| tbl_fk.into());
let primary_keys = table_create
.get_indexes()
.iter()
.filter(|index| index.is_primary_key())
.map(|index| {
index
.get_index_spec()
.get_column_names()
.into_iter()
.map(|name| PrimaryKey { name })
.collect::<Vec<_>>()
})
.flatten()
.collect();
let entity = Entity {
table_name: table_name.clone(),
columns,
relations: relations.clone().collect(),
conjunct_relations: vec![],
primary_keys,
};
entities.insert(table_name.clone(), entity.clone());
for (i, mut rel) in relations.into_iter().enumerate() {
let is_conjunct_relation = entity.primary_keys.len() == entity.columns.len()
&& entity.primary_keys.len() == 2;
match is_conjunct_relation {
true => {
let another_rel = entity.relations.get((i == 0) as usize).unwrap();
let conjunct_relation = ConjunctRelation {
via: table_name.clone(),
to: another_rel.ref_table.clone(),
};
if let Some(vec) = conjunct_relations.get_mut(&rel.ref_table) {
vec.push(conjunct_relation);
} else {
conjunct_relations.insert(rel.ref_table, vec![conjunct_relation]);
}
}
false => {
let ref_table = rel.ref_table;
let mut unique = true;
for column in rel.columns.iter() {
if !entity
.columns
.iter()
.filter(|col| col.unique)
.any(|col| col.name.as_str() == column)
{
unique = false;
break;
}
}
let rel_type = if unique {
RelationType::HasOne
} else {
RelationType::HasMany
};
rel.rel_type = rel_type;
rel.ref_table = table_name.clone();
rel.columns = Vec::new();
rel.ref_columns = Vec::new();
if let Some(vec) = inverse_relations.get_mut(&ref_table) {
vec.push(rel);
} else {
inverse_relations.insert(ref_table, vec![rel]);
}
}
}
}
}
for (tbl_name, mut relations) in inverse_relations.into_iter() {
if let Some(entity) = entities.get_mut(&tbl_name) {
entity.relations.append(&mut relations);
}
}
for (tbl_name, mut conjunct_relations) in conjunct_relations.into_iter() {
if let Some(entity) = entities.get_mut(&tbl_name) {
entity.conjunct_relations.append(&mut conjunct_relations);
}
}
Ok(EntityWriter {
entities: entities.into_iter().map(|(_, v)| v).collect(),
})
}
}