237 lines
13 KiB
Rust
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)
|
|
}
|
|
}
|