use crate::common::column_type_generator::{ColumnTypeGenerator};
use crate::common::generator_context::GeneratorContext;
use schema_model::model::column::Column;
use schema_model::model::column_type::ColumnType;
use schema_model::model::table::Table;
use schema_model::model::types::BooleanMode;
pub trait ColumnGenerator {
fn column_definitions(&self, table: &Table) -> Vec<String>;
fn column_sql(&self, table: &Table, column: &Column) -> String;
fn column_options(&self, table: &Table, column: &Column) -> String;
fn default_value(&self, table: &Table, column: &Column) -> Option<String>;
}
pub struct DefaultColumnGenerator {
context: GeneratorContext,
column_type_generator: Box<dyn ColumnTypeGenerator>,
}
impl DefaultColumnGenerator {
pub fn new(
context: GeneratorContext,
column_type_generator: Box<dyn ColumnTypeGenerator>,
) -> Self {
Self {
column_type_generator,
context,
}
}
fn convert_boolean_default_constraint(&self, value: bool) -> String {
match self.context.settings().boolean_mode() {
BooleanMode::Native => {
if value {
"true".to_string()
} else {
"false".to_string()
}
}
BooleanMode::YesNo => {
if value {
"'Yes'".to_string()
} else {
"'No'".to_string()
}
}
BooleanMode::YN => {
if value {
"'Y'".to_string()
} else {
"'N'".to_string()
}
}
}
}
fn boolean_default_value(&self, default_constraint: Option<&str>) -> Option<String> {
if default_constraint.is_some() {
if default_constraint.unwrap().to_ascii_lowercase() == "null" {
return None;
}
let value = matches!(
default_constraint.unwrap().to_ascii_lowercase().as_str(),
"true"
);
return Some(self.convert_boolean_default_constraint(value));
}
Some(self.convert_boolean_default_constraint(false))
}
fn uuid_default_value(
&self,
table: &Table,
column: &Column,
default_constraint: Option<&str>,
) -> Option<String> {
let schema = self
.context
.settings()
.database_model()
.find_schema(table.schema_name());
let primary_key_columns = table.primary_key_columns();
if column.required()
&& primary_key_columns.is_some()
&& primary_key_columns
.unwrap()
.contains(&column.name().to_string())
&& table.column_relation(column).is_none()
{
return Some(self.column_type_generator.uuid_default_value_sql(schema));
}
if default_constraint.is_some()
&& default_constraint.unwrap().to_ascii_lowercase() == "generate_uuid()"
{
return Some(self.column_type_generator.uuid_default_value_sql(schema));
}
None
}
fn default_constraint(&self, _table: &Table, column: &Column, default_value: &str) -> String {
format!("constraint {} default {}", column.name(), default_value)
}
}
impl ColumnGenerator for DefaultColumnGenerator {
fn column_definitions(&self, table: &Table) -> Vec<String> {
table
.columns()
.iter()
.map(|column| self.column_sql(table, column))
.collect()
}
fn column_sql(&self, table: &Table, column: &Column) -> String {
let column_options = self.column_options(table, column);
if column_options.is_empty() {
return format!(
" {} {}",
column.name(),
self.column_type_generator.column_type_sql(table, column)
);
}
format!(
" {} {} {}",
column.name(),
self.column_type_generator.column_type_sql(table, column),
column_options
)
}
fn column_options(&self, table: &Table, column: &Column) -> String {
let mut options = String::new();
if column.required() {
if column.length() > 0 {
options.push_str(" ");
}
options.push_str("not null")
}
let default_value = self.default_value(table, column);
if default_value.is_some() {
if !options.is_empty() {
options.push_str(" ");
}
options.push_str(self.default_constraint(table, column, default_value.unwrap().as_ref()).as_str());
}
options.trim().to_string()
}
fn default_value(&self, table: &Table, column: &Column) -> Option<String> {
let default_constraint = column.default_constraint();
match column.column_type() {
ColumnType::Boolean => self.boolean_default_value(default_constraint),
ColumnType::Uuid => self.uuid_default_value(table, column, default_constraint),
_ => default_constraint.map(String::from),
}
}
}