-
Notifications
You must be signed in to change notification settings - Fork 216
/
calculate_datamodel.rs
124 lines (106 loc) 路 4.14 KB
/
calculate_datamodel.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::commenting_out_guardrails::commenting_out_guardrails;
use crate::misc_helpers::*;
use crate::sanitize_datamodel_names::sanitize_datamodel_names;
use crate::SqlIntrospectionResult;
use datamodel::{dml, Datamodel, FieldType, Model};
use log::debug;
use sql_schema_describer::*;
/// Calculate a data model from a database schema.
/// todo return warnings
pub fn calculate_model(schema: &SqlSchema) -> SqlIntrospectionResult<Datamodel> {
debug!("Calculating data model.");
let mut data_model = Datamodel::new();
for table in schema
.tables
.iter()
.filter(|table| !is_migration_table(&table))
.filter(|table| !is_prisma_1_point_1_join_table(&table))
.filter(|table| !is_prisma_1_point_0_join_table(&table))
{
debug!("Calculating model: {}", table.name);
let mut model = Model::new(table.name.clone(), None);
for column in &table.columns {
let field = calculate_scalar_field(&table, &column);
model.add_field(field);
}
for foreign_key in &table.foreign_keys {
model.add_field(calculate_relation_field(schema, table, foreign_key));
}
for index in table
.indices
.iter()
.filter(|i| !(i.columns.len() == 1 && i.is_unique()))
{
model.add_index(calculate_index(index));
}
if table.primary_key_columns().len() > 1 {
model.id_fields = table.primary_key_columns();
}
data_model.add_model(model);
}
for e in schema.enums.iter() {
data_model.add_enum(dml::Enum {
name: e.name.clone(),
values: e
.values
.iter()
.map(|v| dml::EnumValue::new(v, None))
.collect(),
database_name: None,
documentation: None,
});
}
let mut fields_to_be_added = Vec::new();
// add backrelation fields
for model in data_model.models.iter() {
for relation_field in model.fields.iter() {
if let FieldType::Relation(relation_info) = &relation_field.field_type {
if data_model
.related_field(
&model.name,
&relation_info.to,
&relation_info.name,
&relation_field.name,
)
.is_none()
{
let other_model = data_model.find_model(relation_info.to.as_str()).unwrap();
let field = calculate_backrelation_field(
schema,
model,
other_model,
relation_field,
relation_info,
);
fields_to_be_added.push((other_model.name.clone(), field));
}
}
}
}
// add prisma many to many relation fields
for table in schema.tables.iter().filter(|table| {
is_prisma_1_point_1_join_table(&table) || is_prisma_1_point_0_join_table(&table)
}) {
if let (Some(f), Some(s)) = (table.foreign_keys.get(0), table.foreign_keys.get(1)) {
let is_self_relation = f.referenced_table == s.referenced_table;
fields_to_be_added.push((
s.referenced_table.clone(),
calculate_many_to_many_field(f, table.name[1..].to_string(), is_self_relation),
));
fields_to_be_added.push((
f.referenced_table.clone(),
calculate_many_to_many_field(s, table.name[1..].to_string(), is_self_relation),
));
}
}
for (model, field) in fields_to_be_added {
let model = data_model.find_model_mut(&model).unwrap();
model.add_field(field);
}
//todo sanitizing might need to be adjusted to also change the fields in the RelationInfo
sanitize_datamodel_names(&mut data_model); //todo warnings
commenting_out_guardrails(&mut data_model); //todo warnings
deduplicate_field_names(&mut data_model);
debug!("Done calculating data model {:?}", data_model);
Ok(data_model)
}