schema_sql_generator/common/
relation_generator.rs1use schema_model::model::database_model::DatabaseModel;
2use schema_model::model::relation::Relation;
3use schema_model::model::table::Table;
4use schema_model::model::types::RelationType;
5use crate::common::generator_context::GeneratorContext;
6use crate::common::sql_writer::SqlWriter;
7
8const FK_PREFIX: &str = "fk_";
9
10pub trait RelationGenerator {
11 fn output_relations(&self);
12}
13
14pub struct DefaultRelationGenerator {
15 context: GeneratorContext,
16}
17
18impl DefaultRelationGenerator {
19 pub fn new(context: GeneratorContext) -> Self {
20 Self {
21 context,
22 }
23 }
24
25 pub fn context(&self) -> &GeneratorContext {
26 &self.context
27 }
28
29 fn output_relation_for_table(&self, writer: &mut SqlWriter, table: &Table) {
30 let database_type = self.context.settings().database_type();
31 let database_model = self.context.settings().database_model();
32 let max_key_name_length = database_type.max_key_name_length();
33 let table_name = table.name();
34 let relations = table.relations();
35
36 for (relation_index, relation) in relations.iter().enumerate() {
37 let mut relation_name = format!("{}{}{}", FK_PREFIX, table_name, relation_index + 1);
38
39 if relation_name.len() > max_key_name_length {
40 let truncated_table_name_len = max_key_name_length - FK_PREFIX.len() - 1; let truncated_table_name = &table_name[..truncated_table_name_len.min(table_name.len())];
42 relation_name = format!("{}{}{}", FK_PREFIX, truncated_table_name, relation_index + 1);
43 }
44
45 self.output_relation(writer, &relation_name.to_lowercase(), database_model, table, relation);
46 }
47 }
48
49 fn output_relation(&self,
50 writer: &mut SqlWriter,
51 relation_name: &str,
52 database_model: &DatabaseModel,
53 table: &Table,
54 relation: &Relation) {
55 let operation = self.relation_operation_type(relation.relation_type());
56 let to_table = self.find_table(relation.to_table_name(), database_model);
57
58 writer.print(format!("alter table {}", table.fully_qualified_table_name()).as_str());
59 writer.print(" add constraint ");
60 writer.print(relation_name);
61 writer.print(" foreign key (");
62 writer.print(relation.from_column_name());
63 writer.print(") references ");
64 writer.print(to_table.fully_qualified_table_name().as_str());
65 writer.print("(");
66 writer.print(relation.to_column_name());
67 writer.print(") on delete ");
68 writer.print(operation);
69 writer.println(self.context().settings().statement_separator());
70 }
71
72 fn relation_operation_type(&self, relation_type: RelationType) -> &str {
73 match relation_type {
74 RelationType::Cascade => {"cascade"}
75 RelationType::Enforce => {"no action"}
76 RelationType::SetNull => {"set null"}
77 RelationType::DoNothing => {"no action"}
78 }
79 }
80
81 fn find_table<'a>(&self, to_table_name: &str, database_model: &'a DatabaseModel) -> &'a Table {
82 let parts: Vec<&str> = to_table_name.split('.').collect();
83 let (schema, table_name) = if parts.len() == 2 {
84 (Some(parts[0]), parts[1])
85 } else {
86 (None, to_table_name)
87 };
88
89 database_model.find_table(schema, table_name)
90 }
91}
92
93impl RelationGenerator for DefaultRelationGenerator {
94 fn output_relations(&self) {
95 let database_model = self.context.settings().database_model();
96 let has_relations = database_model.all_tables().iter().any(|table| {!table.relations().is_empty()});
97
98 if has_relations {
99 self.context.with_writer(|writer| {
100 writer.println("/* relations */");
101
102 database_model.all_tables().iter().filter(|table| {
103 !table.relations().is_empty()
104 }).for_each(|table| {
105 self.output_relation_for_table(writer, table);
106 });
107
108 writer.newline();
109 });
110 }
111 }
112}