Files
sea-orm-generator/src/generator/models/column.rs

237 lines
13 KiB
Rust

use color_eyre::{eyre::ContextCompat, Result};
use comfy_table::Cell;
use heck::ToUpperCamelCase;
use sea_schema::sea_query::{ColumnDef, ColumnSpec, ColumnType, IndexCreateStatement};
use crate::config::{sea_orm_config::DateTimeCrate, Config};
use super::{discover::DbType, ModelConfig};
#[derive(Clone, Debug)]
pub struct Column {
pub name: String,
pub col_type: ColumnType,
pub attrs: Vec<ColumnSpec>,
}
impl Column {
pub fn new(column: ColumnDef, index: Option<IndexCreateStatement>) -> Result<Self> {
let name = column.get_column_name();
let col_type = column
.get_column_type()
.context("Unable to get column type")?
.clone();
let mut attrs = column.get_column_spec().clone();
if let Some(index) = index {
if index.is_unique_key() {
attrs.push(ColumnSpec::UniqueKey)
}
if index.is_primary_key() {
attrs.push(ColumnSpec::PrimaryKey);
}
}
Ok(Column {
name: name.to_string(),
col_type,
attrs: attrs.to_vec(),
})
}
pub fn get_info_row(&self, config: &ModelConfig) -> Result<Vec<Cell>> {
let column_type_rust = self.get_rs_type(&config.comment.date_time_crate);
let column_type = self.get_db_type(&config.db_type);
let attrs = self.attrs_to_string();
let mut cols = Vec::new();
if config.comment.column_name {
cols.push(Cell::new(self.name.clone()))
}
if config.comment.column_name {
cols.push(Cell::new(column_type.clone()))
}
if config.comment.column_rust_type {
cols.push(Cell::new(column_type_rust.clone()))
}
if config.comment.column_attributes {
cols.push(Cell::new(attrs.clone()));
}
Ok(cols)
}
pub fn attrs_to_string(&self) -> String {
self.attrs
.iter()
.filter_map(Self::get_addr_type)
.map(|s| s.to_string())
.collect::<Vec<String>>()
.join(", ")
}
pub fn get_addr_type(attr: &ColumnSpec) -> Option<String> {
match attr {
ColumnSpec::PrimaryKey => Some("primary key".to_owned()),
ColumnSpec::Null => todo!(),
ColumnSpec::NotNull => Some("not null".to_owned()),
ColumnSpec::Default(simple_expr) => todo!(),
ColumnSpec::AutoIncrement => Some("autoincrement".to_owned()),
ColumnSpec::UniqueKey => Some("unique key".to_owned()),
ColumnSpec::Check(simple_expr) => todo!(),
ColumnSpec::Generated { expr, stored } => todo!(),
ColumnSpec::Extra(_) => todo!(),
ColumnSpec::Comment(_) => todo!(),
}
}
pub fn get_db_type(&self, db_type: &DbType) -> String {
fn write_db_type(col_type: &ColumnType, db_type: &DbType) -> String {
#[allow(unreachable_patterns)]
match (col_type, db_type) {
(ColumnType::Char(_), _) => "char".to_owned(),
(ColumnType::String(_), _) => "varchar".to_owned(),
(ColumnType::Text, _) => "text".to_owned(),
(ColumnType::TinyInteger, DbType::MySql | DbType::Sqlite) => "tinyint".to_owned(),
(ColumnType::TinyInteger, DbType::Postgres) => "smallint".to_owned(),
(ColumnType::SmallInteger, _) => "smallint".to_owned(),
(ColumnType::Integer, DbType::MySql) => "int".to_owned(),
(ColumnType::Integer, _) => "integer".to_owned(),
(ColumnType::BigInteger, DbType::MySql | DbType::Postgres) => "bigint".to_owned(),
(ColumnType::BigInteger, DbType::Sqlite) => "integer".to_owned(),
(ColumnType::TinyUnsigned, DbType::MySql) => "tinyint unsigned".to_owned(),
(ColumnType::TinyUnsigned, DbType::Postgres) => "smallint".to_owned(),
(ColumnType::TinyUnsigned, DbType::Sqlite) => "tinyint".to_owned(),
(ColumnType::SmallUnsigned, DbType::MySql) => "smallint unsigned".to_owned(),
(ColumnType::SmallUnsigned, DbType::Postgres | DbType::Sqlite) => {
"smallint".to_owned()
}
(ColumnType::Unsigned, DbType::MySql) => "int unsigned".to_owned(),
(ColumnType::Unsigned, DbType::Postgres | DbType::Sqlite) => "integer".to_owned(),
(ColumnType::BigUnsigned, DbType::MySql) => "bigint unsigned".to_owned(),
(ColumnType::BigUnsigned, DbType::Postgres) => "bigint".to_owned(),
(ColumnType::BigUnsigned, DbType::Sqlite) => "integer".to_owned(),
(ColumnType::Float, DbType::MySql | DbType::Sqlite) => "float".to_owned(),
(ColumnType::Float, DbType::Postgres) => "real".to_owned(),
(ColumnType::Double, DbType::MySql | DbType::Sqlite) => "double".to_owned(),
(ColumnType::Double, DbType::Postgres) => "double precision".to_owned(),
(ColumnType::Decimal(_), DbType::MySql | DbType::Postgres) => "decimal".to_owned(),
(ColumnType::Decimal(_), DbType::Sqlite) => "real".to_owned(),
(ColumnType::DateTime, DbType::MySql) => "datetime".to_owned(),
(ColumnType::DateTime, DbType::Postgres) => "timestamp w/o tz".to_owned(),
(ColumnType::DateTime, DbType::Sqlite) => "datetime_text".to_owned(),
(ColumnType::Timestamp, DbType::MySql | DbType::Postgres) => "timestamp".to_owned(),
(ColumnType::Timestamp, DbType::Sqlite) => "timestamp_text".to_owned(),
(ColumnType::TimestampWithTimeZone, DbType::MySql) => "timestamp".to_owned(),
(ColumnType::TimestampWithTimeZone, DbType::Postgres) => {
"timestamp w tz".to_owned()
}
(ColumnType::TimestampWithTimeZone, DbType::Sqlite) => {
"timestamp_with_timezone_text".to_owned()
}
(ColumnType::Time, DbType::MySql | DbType::Postgres) => "time".to_owned(),
(ColumnType::Time, DbType::Sqlite) => "time_text".to_owned(),
(ColumnType::Date, DbType::MySql | DbType::Postgres) => "date".to_owned(),
(ColumnType::Date, DbType::Sqlite) => "date_text".to_owned(),
(ColumnType::Year, DbType::MySql) => "year".to_owned(),
(ColumnType::Interval(_, _), DbType::Postgres) => "interval".to_owned(),
(ColumnType::Blob, DbType::MySql | DbType::Sqlite) => "blob".to_owned(),
(ColumnType::Blob, DbType::Postgres) => "bytea".to_owned(),
(ColumnType::Binary(_), DbType::MySql) => "binary".to_owned(),
(ColumnType::Binary(_), DbType::Postgres) => "bytea".to_owned(),
(ColumnType::Binary(_), DbType::Sqlite) => "blob".to_owned(),
(ColumnType::VarBinary(_), DbType::MySql) => "varbinary".to_owned(),
(ColumnType::VarBinary(_), DbType::Postgres) => "bytea".to_owned(),
(ColumnType::VarBinary(_), DbType::Sqlite) => "varbinary_blob".to_owned(),
(ColumnType::Bit(_), DbType::MySql | DbType::Postgres) => "bit".to_owned(),
(ColumnType::VarBit(_), DbType::MySql) => "bit".to_owned(),
(ColumnType::VarBit(_), DbType::Postgres) => "varbit".to_owned(),
(ColumnType::Boolean, DbType::MySql | DbType::Postgres) => "bool".to_owned(),
(ColumnType::Boolean, DbType::Sqlite) => "boolean".to_owned(),
(ColumnType::Money(_), DbType::MySql) => "decimal".to_owned(),
(ColumnType::Money(_), DbType::Postgres) => "money".to_owned(),
(ColumnType::Money(_), DbType::Sqlite) => "real_money".to_owned(),
(ColumnType::Json, DbType::MySql | DbType::Postgres) => "json".to_owned(),
(ColumnType::Json, DbType::Sqlite) => "json_text".to_owned(),
(ColumnType::JsonBinary, DbType::MySql) => "json".to_owned(),
(ColumnType::JsonBinary, DbType::Postgres) => "jsonb".to_owned(),
(ColumnType::JsonBinary, DbType::Sqlite) => "jsonb_text".to_owned(),
(ColumnType::Uuid, DbType::MySql) => "binary(16)".to_owned(),
(ColumnType::Uuid, DbType::Postgres) => "uuid".to_owned(),
(ColumnType::Uuid, DbType::Sqlite) => "uuid_text".to_owned(),
(ColumnType::Enum { name, .. }, DbType::MySql) => {
format!("ENUM({})", name.to_string().to_upper_camel_case())
}
(ColumnType::Enum { name, .. }, DbType::Postgres) => {
name.to_string().to_uppercase()
}
(ColumnType::Enum { .. }, DbType::Sqlite) => "enum_text".to_owned(),
(ColumnType::Array(column_type), DbType::Postgres) => {
format!("{}[]", write_db_type(column_type, db_type)).to_uppercase()
}
(ColumnType::Vector(_), DbType::Postgres) => "vector".to_owned(),
(ColumnType::Cidr, DbType::Postgres) => "cidr".to_owned(),
(ColumnType::Inet, DbType::Postgres) => "inet".to_owned(),
(ColumnType::MacAddr, DbType::Postgres) => "macaddr".to_owned(),
(ColumnType::LTree, DbType::Postgres) => "ltree".to_owned(),
_ => unimplemented!(),
}
}
write_db_type(&self.col_type, db_type)
}
pub fn get_rs_type(&self, date_time_crate: &DateTimeCrate) -> String {
fn write_rs_type(col_type: &ColumnType, date_time_crate: &DateTimeCrate) -> String {
#[allow(unreachable_patterns)]
match col_type {
ColumnType::Char(_)
| ColumnType::String(_)
| ColumnType::Text
| ColumnType::Custom(_) => "String".to_owned(),
ColumnType::TinyInteger => "i8".to_owned(),
ColumnType::SmallInteger => "i16".to_owned(),
ColumnType::Integer => "i32".to_owned(),
ColumnType::BigInteger => "i64".to_owned(),
ColumnType::TinyUnsigned => "u8".to_owned(),
ColumnType::SmallUnsigned => "u16".to_owned(),
ColumnType::Unsigned => "u32".to_owned(),
ColumnType::BigUnsigned => "u64".to_owned(),
ColumnType::Float => "f32".to_owned(),
ColumnType::Double => "f64".to_owned(),
ColumnType::Json | ColumnType::JsonBinary => "Json".to_owned(),
ColumnType::Date => match date_time_crate {
DateTimeCrate::Chrono => "Date".to_owned(),
DateTimeCrate::Time => "TimeDate".to_owned(),
},
ColumnType::Time => match date_time_crate {
DateTimeCrate::Chrono => "Time".to_owned(),
DateTimeCrate::Time => "TimeTime".to_owned(),
},
ColumnType::DateTime => match date_time_crate {
DateTimeCrate::Chrono => "DateTime".to_owned(),
DateTimeCrate::Time => "TimeDateTime".to_owned(),
},
ColumnType::Timestamp => match date_time_crate {
DateTimeCrate::Chrono => "DateTimeUtc".to_owned(),
DateTimeCrate::Time => "TimeDateTime".to_owned(),
},
ColumnType::TimestampWithTimeZone => match date_time_crate {
DateTimeCrate::Chrono => "DateTimeWithTimeZone".to_owned(),
DateTimeCrate::Time => "TimeDateTimeWithTimeZone".to_owned(),
},
ColumnType::Decimal(_) | ColumnType::Money(_) => "Decimal".to_owned(),
ColumnType::Uuid => "Uuid".to_owned(),
ColumnType::Binary(_) | ColumnType::VarBinary(_) | ColumnType::Blob => {
"Vec<u8>".to_owned()
}
ColumnType::Boolean => "bool".to_owned(),
ColumnType::Enum { name, .. } => name.to_string().to_upper_camel_case(),
ColumnType::Array(column_type) => {
format!("Vec<{}>", write_rs_type(column_type, date_time_crate))
}
ColumnType::Vector(_) => "::pgvector::Vector".to_owned(),
ColumnType::Bit(None | Some(1)) => "bool".to_owned(),
ColumnType::Bit(_) | ColumnType::VarBit(_) => "Vec<u8>".to_owned(),
ColumnType::Year => "i32".to_owned(),
ColumnType::Cidr | ColumnType::Inet => "IpNetwork".to_owned(),
ColumnType::Interval(_, _) | ColumnType::MacAddr | ColumnType::LTree => {
"String".to_owned()
}
_ => unimplemented!(),
}
}
write_rs_type(&self.col_type, date_time_crate)
}
}