Skip to main content

schema_sql_generator/common/
index_generator.rs

1use crate::common::generator_context::GeneratorContext;
2use crate::common::sql_writer::SqlWriter;
3use schema_model::model::key::Key;
4use schema_model::model::table::Table;
5
6const IX_PREFIX: &str = "ix_";
7
8pub trait IndexGenerator {
9    fn output_indexes(&self);
10
11    fn output_indexes_for_table(&self, writer: &mut SqlWriter, table: &Table);
12
13    fn output_index(
14        &self,
15        writer: &mut SqlWriter,
16        statement_separator: &str,
17        table: &Table,
18        key_name: &str,
19        key: &Key,
20    );
21
22    fn index_options(&self, key: &Key) -> Option<String>;
23}
24
25pub struct DefaultIndexGenerator {
26    context: GeneratorContext,
27}
28
29impl DefaultIndexGenerator {
30    pub fn new(context: GeneratorContext) -> Self {
31        Self { context }
32    }
33
34    pub fn context(&self) -> &GeneratorContext {
35        &self.context
36    }
37}
38
39impl IndexGenerator for DefaultIndexGenerator {
40    fn output_indexes(&self) {
41        let database_model = self.context.settings().database_model();
42
43        self.context.with_writer(|writer| {
44            database_model.schemas().iter().for_each(|schema| {
45                schema.tables().iter().for_each(|table| {
46                    self.output_indexes_for_table(writer, table);
47                });
48            });
49        });
50    }
51
52    fn output_indexes_for_table(&self, writer: &mut SqlWriter, table: &Table) {
53        if !table.indexes().is_empty() {
54            let max_key_name_length = self
55                .context()
56                .settings()
57                .database_type()
58                .max_key_name_length();
59
60            for (key_index, key) in table
61                .indexes()
62                .iter()
63                .filter(|key| key.is_index())
64                .enumerate()
65            {
66                let mut key_name = format!("{}{}{}", IX_PREFIX, table.name(), key_index + 1);
67
68                if key_name.len() > max_key_name_length {
69                    let max_name_len = max_key_name_length.saturating_sub(4); // match Java logic
70                    let truncated = table
71                        .name()
72                        .chars()
73                        .take(max_name_len.min(table.name().len()))
74                        .collect::<String>();
75                    key_name = format!("{}{}{}", IX_PREFIX, truncated, key_index + 1);
76                }
77
78                self.output_index(
79                    writer,
80                    self.context().settings().statement_separator(),
81                    table,
82                    key_name.as_str(),
83                    key,
84                );
85            }
86
87            writer.newline();
88        }
89    }
90
91    fn output_index(
92        &self,
93        writer: &mut SqlWriter,
94        statement_separator: &str,
95        table: &Table,
96        key_name: &str,
97        key: &Key,
98    ) {
99        let index_options = self.index_options(key);
100        let index_columns = key
101            .columns()
102            .iter()
103            .map(|column| column.name())
104            .collect::<Vec<_>>()
105            .join(", ");
106
107        if index_options.is_some() {
108            writer.println(
109                format!(
110                    "create {}index {} on {} ({}) {}{}",
111                    if key.is_unique() { "unique " } else { "" },
112                    key_name,
113                    table.name(),
114                    index_columns,
115                    index_options.unwrap(),
116                    statement_separator
117                )
118                    .as_str(),
119            );
120        } else {
121            writer.println(
122                format!(
123                    "create {}index {} on {} ({}){}",
124                    if key.is_unique() { "unique " } else { "" },
125                    key_name,
126                    table.name(),
127                    index_columns,
128                    statement_separator
129                )
130                    .as_str(),
131            );
132        }
133    }
134
135    fn index_options(&self, _key: &Key) -> Option<String> {
136        None
137    }
138}