schema_sql_generator/common/
column_generator.rs1use 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}