Skip to main content

schema_sql_generator/common/
column_generator.rs

1use crate::common::column_type_generator::{ColumnTypeGenerator};
2use crate::common::generator_context::GeneratorContext;
3use schema_model::model::column::Column;
4use schema_model::model::column_type::ColumnType;
5use schema_model::model::table::Table;
6use schema_model::model::types::BooleanMode;
7
8pub trait ColumnGenerator {
9    fn column_definitions(&self, table: &Table) -> Vec<String>;
10
11    fn column_sql(&self, table: &Table, column: &Column) -> String;
12
13    fn column_options(&self, table: &Table, column: &Column) -> String;
14
15    fn default_value(&self, table: &Table, column: &Column) -> Option<String>;
16}
17
18pub struct DefaultColumnGenerator {
19    context: GeneratorContext,
20    column_type_generator: Box<dyn ColumnTypeGenerator>,
21}
22
23impl DefaultColumnGenerator {
24    pub fn new(
25        context: GeneratorContext,
26        column_type_generator: Box<dyn ColumnTypeGenerator>,
27    ) -> Self {
28        Self {
29            column_type_generator,
30            context,
31        }
32    }
33
34    fn convert_boolean_default_constraint(&self, value: bool) -> String {
35        match self.context.settings().boolean_mode() {
36            BooleanMode::Native => {
37                if value {
38                    "true".to_string()
39                } else {
40                    "false".to_string()
41                }
42            }
43            BooleanMode::YesNo => {
44                if value {
45                    "'Yes'".to_string()
46                } else {
47                    "'No'".to_string()
48                }
49            }
50            BooleanMode::YN => {
51                if value {
52                    "'Y'".to_string()
53                } else {
54                    "'N'".to_string()
55                }
56            }
57        }
58    }
59
60    fn boolean_default_value(&self, default_constraint: Option<&str>) -> Option<String> {
61        if default_constraint.is_some() {
62            if default_constraint.unwrap().to_ascii_lowercase() == "null" {
63                return None;
64            }
65
66            let value = matches!(
67                default_constraint.unwrap().to_ascii_lowercase().as_str(),
68                "true"
69            );
70            return Some(self.convert_boolean_default_constraint(value));
71        }
72
73        Some(self.convert_boolean_default_constraint(false))
74    }
75
76    fn uuid_default_value(
77        &self,
78        table: &Table,
79        column: &Column,
80        default_constraint: Option<&str>,
81    ) -> Option<String> {
82        let schema = self
83            .context
84            .settings()
85            .database_model()
86            .find_schema(table.schema_name());
87        let primary_key_columns = table.primary_key_columns();
88
89        if column.required()
90            && primary_key_columns.is_some()
91            && primary_key_columns
92                .unwrap()
93                .contains(&column.name().to_string())
94            && table.column_relation(column).is_none()
95        {
96            return Some(self.column_type_generator.uuid_default_value_sql(schema));
97        }
98
99        if default_constraint.is_some()
100            && default_constraint.unwrap().to_ascii_lowercase() == "generate_uuid()"
101        {
102            return Some(self.column_type_generator.uuid_default_value_sql(schema));
103        }
104
105        None
106    }
107
108    fn default_constraint(&self, _table: &Table, column: &Column, default_value: &str) -> String {
109        format!("constraint {} default {}", column.name(), default_value)
110    }
111}
112
113impl ColumnGenerator for DefaultColumnGenerator {
114    fn column_definitions(&self, table: &Table) -> Vec<String> {
115        table
116            .columns()
117            .iter()
118            .map(|column| self.column_sql(table, column))
119            .collect()
120    }
121
122    fn column_sql(&self, table: &Table, column: &Column) -> String {
123        let column_options = self.column_options(table, column);
124
125        if column_options.is_empty() {
126            return format!(
127                "   {} {}",
128                column.name(),
129                self.column_type_generator.column_type_sql(table, column)
130            );
131        }
132
133        format!(
134            "   {} {} {}",
135            column.name(),
136            self.column_type_generator.column_type_sql(table, column),
137            column_options
138        )
139    }
140
141    fn column_options(&self, table: &Table, column: &Column) -> String {
142        let mut options = String::new();
143
144        if column.required() {
145            if column.length() > 0 {
146                options.push_str(" ");
147            }
148
149            options.push_str("not null")
150        }
151
152        let default_value = self.default_value(table, column);
153
154        if default_value.is_some() {
155            if !options.is_empty() {
156                options.push_str(" ");
157            }
158
159            options.push_str(self.default_constraint(table, column, default_value.unwrap().as_ref()).as_str());
160        }
161
162        options.trim().to_string()
163    }
164
165    fn default_value(&self, table: &Table, column: &Column) -> Option<String> {
166        let default_constraint = column.default_constraint();
167
168        match column.column_type() {
169            ColumnType::Boolean => self.boolean_default_value(default_constraint),
170            ColumnType::Uuid => self.uuid_default_value(table, column, default_constraint),
171            _ => default_constraint.map(String::from),
172        }
173    }
174}