really work.
use sea_orm_migration::prelude::*;
use sea_orm_migration::sea_orm::DbErr;
#[derive(Debug, Clone)]
pub enum ColumnType {
Integer,
BigInteger,
String,
Text,
Boolean,
DateTime,
Timestamp,
Uuid,
Json,
}
#[derive(Debug, Clone)]
pub struct Column {
pub name: &'static str,
pub ty: ColumnType,
pub nullable: bool,
pub primary_key: bool,
pub unique: bool,
}
impl Column {
pub const fn new(
name: &'static str,
ty: ColumnType,
nullable: bool,
primary_key: bool,
unique: bool,
) -> Self {
Self {
name,
ty,
nullable,
primary_key,
unique,
}
}
}
#[derive(Debug, Clone)]
struct DynIden(String);
impl DynIden {
fn new(name: impl Into<String>) -> Self {
Self(name.into())
}
}
impl Iden for DynIden {
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
write!(s, "{}", self.0).unwrap();
}
}
/// ```ignore
/// create_table(
/// manager,
/// "users",
/// &[
/// col!(id: integer, primary_key: true),
/// col!(email: string, nullable: false, unique: true),
/// col!(name: string),
/// col!(created_at: timestamp, nullable: false),
/// ],
/// )
/// .await?;
/// ```
pub async fn create_table(
m: &SchemaManager<'_>,
table: &str,
cols: &[Column],
timestamps: bool,
) -> Result<(), DbErr> {
let mut stmt = Table::create();
stmt.table(DynIden::new(table)).if_not_exists();
for col in cols {
stmt.col(build_column_def(col));
}
if timestamps {
stmt.col(build_column_def(&Column::new(
"created_at",
ColumnType::Timestamp,
false,
false,
false,
)));
stmt.col(build_column_def(&Column::new(
"updated_at",
ColumnType::Timestamp,
false,
false,
false,
)));
}
m.create_table(stmt).await
}
pub async fn create_table_with_timestamps(
m: &SchemaManager<'_>,
table: &str,
cols: &[Column],
) -> Result<(), DbErr> {
create_table(m, table, cols, true).await
}
fn build_column_def(col: &Column) -> ColumnDef {
let mut def = ColumnDef::new(DynIden::new(col.name));
match col.ty {
ColumnType::Integer => {
def.integer();
}
ColumnType::BigInteger => {
def.big_integer();
}
ColumnType::String => {
def.string();
}
ColumnType::Text => {
def.text();
}
ColumnType::Boolean => {
def.boolean();
}
ColumnType::DateTime => {
def.date_time();
}
ColumnType::Timestamp => {
def.timestamp();
}
ColumnType::Uuid => {
def.uuid();
}
ColumnType::Json => {
def.json();
}
}
if col.primary_key {
def.not_null();
def.primary_key();
match col.ty {
ColumnType::Integer | ColumnType::BigInteger => {
def.auto_increment();
}
_ => {}
}
} else if !col.nullable {
def.not_null();
}
if col.unique && !col.primary_key {
def.unique_key();
}
def
}
/// ```ignore
/// col!(id: integer)
/// col!(email: string, nullable: false)
/// col!(email: string, nullable: false, unique: true)
/// col!(id: integer, nullable: false, primary_key: true, unique: true)
/// ```
#[macro_export]
macro_rules! col {
(
$name:ident : $ty:ident
$(, nullable: $nullable:expr)?
$(, primary_key: $primary_key:expr)?
$(, unique: $unique:expr)?
$(,)?
) => {
$crate::Column::new(
stringify!($name),
$crate::col_type!($ty),
$crate::__col_or_default_bool!(true $(, $nullable)?),
$crate::__col_or_default_bool!(false $(, $primary_key)?),
$crate::__col_or_default_bool!(false $(, $unique)?),
)
};
}
#[macro_export]
macro_rules! col_type {
(integer) => {
$crate::ColumnType::Integer
};
(int) => {
$crate::ColumnType::Integer
};
(big_integer) => {
$crate::ColumnType::BigInteger
};
(bigint) => {
$crate::ColumnType::BigInteger
};
(string) => {
$crate::ColumnType::String
};
(varchar) => {
$crate::ColumnType::String
};
(text) => {
$crate::ColumnType::Text
};
(bool) => {
$crate::ColumnType::Boolean
};
(boolean) => {
$crate::ColumnType::Boolean
};
(datetime) => {
$crate::ColumnType::DateTime
};
(date_time) => {
$crate::ColumnType::DateTime
};
(timestamp) => {
$crate::ColumnType::Timestamp
};
(uuid) => {
$crate::ColumnType::Uuid
};
(json) => {
$crate::ColumnType::Json
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __col_or_default_bool {
($default:expr) => {
$default
};
($default:expr, $value:expr) => {
$value
};
}
current data type is a confusion, String, StringNull, StringUniq
I chat with ChatGPT, it gives me a lib
really work.