Replace SeaORM's ColumnType (#1395)

* Replace SeaORM's `ColumnType`

* Bump SeaQuery's version

* Fix merge conflict

* refactor
This commit is contained in:
Billy Chan 2023-01-29 11:06:01 +08:00 committed by GitHub
parent e0e5372efc
commit 08a5e87e22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 38 additions and 234 deletions

View File

@ -95,9 +95,7 @@ impl Column {
ColumnType::Money(Some((p, s))) => Some(format!("Money(Some({p}, {s}))")), ColumnType::Money(Some((p, s))) => Some(format!("Money(Some({p}, {s}))")),
ColumnType::Text => Some("Text".to_owned()), ColumnType::Text => Some("Text".to_owned()),
ColumnType::JsonBinary => Some("JsonBinary".to_owned()), ColumnType::JsonBinary => Some("JsonBinary".to_owned()),
ColumnType::Custom(iden) => { ColumnType::Custom(iden) => Some(format!("custom(\"{}\")", iden.to_string())),
Some(format!("Custom(\"{}\".to_owned())", iden.to_string()))
}
_ => None, _ => None,
}; };
col_type.map(|ty| quote! { column_type = #ty }) col_type.map(|ty| quote! { column_type = #ty })
@ -152,7 +150,7 @@ impl Column {
ColumnType::Uuid => quote! { ColumnType::Uuid }, ColumnType::Uuid => quote! { ColumnType::Uuid },
ColumnType::Custom(s) => { ColumnType::Custom(s) => {
let s = s.to_string(); let s = s.to_string();
quote! { ColumnType::Custom(#s.to_owned()) } quote! { ColumnType::custom(#s) }
} }
ColumnType::Enum { name, .. } => { ColumnType::Enum { name, .. } => {
let enum_ident = format_ident!("{}", name.to_string().to_camel_case()); let enum_ident = format_ident!("{}", name.to_string().to_camel_case());
@ -465,7 +463,7 @@ mod tests {
let columns = setup(); let columns = setup();
let col_defs = vec![ let col_defs = vec![
"ColumnType::String(Some(255u32)).def()", "ColumnType::String(Some(255u32)).def()",
"ColumnType::Custom(\"cus_col\".to_owned()).def()", "ColumnType::custom(\"cus_col\").def()",
"ColumnType::TinyInteger.def()", "ColumnType::TinyInteger.def()",
"ColumnType::TinyUnsigned.def()", "ColumnType::TinyUnsigned.def()",
"ColumnType::SmallInteger.def()", "ColumnType::SmallInteger.def()",

View File

@ -274,8 +274,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
field_type.as_str() field_type.as_str()
}; };
let col_type = match sql_type { let sea_query_col_type = match sql_type {
Some(t) => quote! { sea_orm::prelude::ColumnType::#t.def() }, Some(t) => quote! { sea_orm::prelude::ColumnType::#t },
None => { None => {
let col_type = match field_type { let col_type = match field_type {
"char" => quote! { Char(None) }, "char" => quote! { Char(None) },
@ -302,7 +302,9 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
"Uuid" => quote! { Uuid }, "Uuid" => quote! { Uuid },
"Json" => quote! { Json }, "Json" => quote! { Json },
"Decimal" => quote! { Decimal(None) }, "Decimal" => quote! { Decimal(None) },
"Vec<u8>" => quote! { Binary }, "Vec<u8>" => {
quote! { Binary(sea_orm::sea_query::BlobSize::Blob(None)) }
}
_ => { _ => {
// Assumed it's ActiveEnum if none of the above type matches // Assumed it's ActiveEnum if none of the above type matches
quote! {} quote! {}
@ -311,20 +313,21 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
if col_type.is_empty() { if col_type.is_empty() {
let field_span = field.span(); let field_span = field.span();
let ty: Type = LitStr::new(field_type, field_span).parse()?; let ty: Type = LitStr::new(field_type, field_span).parse()?;
let def = quote_spanned! { field_span => { let def = quote_spanned! { field_span =>
std::convert::Into::<sea_orm::ColumnType>::into( std::convert::Into::<sea_orm::ColumnType>::into(
<#ty as sea_orm::sea_query::ValueType>::column_type() <#ty as sea_orm::sea_query::ValueType>::column_type()
) )
.def() };
}};
quote! { #def } quote! { #def }
} else { } else {
quote! { sea_orm::prelude::ColumnType::#col_type.def() } quote! { sea_orm::prelude::ColumnType::#col_type }
} }
} }
}; };
let col_def =
quote! { sea_orm::prelude::ColumnTypeTrait::def(#sea_query_col_type) };
let mut match_row = quote! { Self::#field_name => #col_type }; let mut match_row = quote! { Self::#field_name => #col_def };
if nullable { if nullable {
match_row = quote! { #match_row.nullable() }; match_row = quote! { #match_row.nullable() };
} }

View File

@ -4,6 +4,10 @@ use sea_query::{
}; };
use std::str::FromStr; use std::str::FromStr;
// The original `sea_orm::ColumnType` enum was dropped since 0.11.0
// It was replaced by `sea_query::ColumnType`, we reexport it here to keep the `ColumnType` symbol
pub use sea_query::ColumnType;
/// Defines a Column for an Entity /// Defines a Column for an Entity
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ColumnDef { pub struct ColumnDef {
@ -14,109 +18,6 @@ pub struct ColumnDef {
pub(crate) default_value: Option<Value>, pub(crate) default_value: Option<Value>,
} }
/// The type of column as defined in the SQL format
#[derive(Debug, Clone)]
pub enum ColumnType {
/// `CHAR` type of specified fixed length
Char(Option<u32>),
/// `STRING` type for variable string length
String(Option<u32>),
/// `TEXT` type used for large pieces of string data and stored out of row in case size is too big
Text,
/// `TINYINT` useful for storing one byte of data (range of 0-255)
TinyInteger,
/// `SMALLINT` data type stores small whole numbers that range from 32,767 to 32,767
SmallInteger,
/// `INTEGER` data types hold numbers that are whole, or without a decimal point
Integer,
/// `BIGINT` is a 64-bit representation of an integer taking up 8 bytes of storage and
/// ranging from -2^63 (-9,223,372,036,854,775,808) to 2^63 (9,223,372,036,854,775,807).
BigInteger,
/// `TINYINT UNSIGNED` data type
TinyUnsigned,
/// `SMALLINT UNSIGNED` data type
SmallUnsigned,
/// `INTEGER UNSIGNED` data type
Unsigned,
/// `BIGINT UNSIGNED` data type
BigUnsigned,
/// `FLOAT` an approximate-number data type, where values range cannot be represented exactly.
Float,
/// `DOUBLE` is a normal-size floating point number where the
/// total number of digits is specified in size.
Double,
/// `DECIMAL` type store numbers that have fixed precision and scale
Decimal(Option<(u32, u32)>),
/// `DATETIME` type is used for values that contain both date and time parts.
DateTime,
/// `TIMESTAMP` is a temporal data type that holds the combination of date and time.
Timestamp,
/// `TIMESTAMP WITH TIME ZONE` (or `TIMESTAMPTZ`) data type stores 8-byte
/// date values that include timestamp and time zone information in UTC format.
TimestampWithTimeZone,
/// `TIME` data type defines a time of a day based on 24-hour clock
Time,
/// `DATE` data type stores the calendar date
Date,
/// `BINARY` data types contain byte strings—a sequence of octets or bytes.
Binary,
/// Tiny Binary
TinyBinary,
/// Medium Binary
MediumBinary,
/// Long Binary
LongBinary,
/// `BOOLEAN` is the result of a comparison operator
Boolean,
/// `MONEY` data type handles monetary data
Money(Option<(u32, u32)>),
/// `JSON` represents the JavaScript Object Notation type
Json,
/// JSON binary format is structured in the way that permits the server to search for
/// values within the JSON document directly by key or array index, which is very fast.
JsonBinary,
/// A custom implementation of a data type
Custom(String),
/// A Universally Unique IDentifier that is specified in RFC 4122
Uuid,
/// `ENUM` data type with name and variants
Enum {
/// Name of enum
name: DynIden,
/// Variants of enum
variants: Vec<DynIden>,
},
/// Array of a specific data type (PostgreSQL only)
Array(SeaRc<ColumnType>),
}
impl PartialEq for ColumnType {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Char(l0), Self::Char(r0)) => l0 == r0,
(Self::String(l0), Self::String(r0)) => l0 == r0,
(Self::Decimal(l0), Self::Decimal(r0)) => l0 == r0,
(Self::Money(l0), Self::Money(r0)) => l0 == r0,
(Self::Custom(l0), Self::Custom(r0)) => l0 == r0,
(
Self::Enum {
name: l_name,
variants: l_variants,
},
Self::Enum {
name: r_name,
variants: r_variants,
},
) => {
l_name.to_string() == r_name.to_string()
&& l_variants.iter().map(|v| v.to_string()).collect::<Vec<_>>()
== r_variants.iter().map(|v| v.to_string()).collect::<Vec<_>>()
}
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
macro_rules! bind_oper { macro_rules! bind_oper {
( $op: ident ) => { ( $op: ident ) => {
#[allow(missing_docs)] #[allow(missing_docs)]
@ -378,9 +279,17 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
} }
} }
impl ColumnType { /// SeaORM's utility methods that act on [ColumnType]
/// instantiate a new [ColumnDef] pub trait ColumnTypeTrait {
pub fn def(self) -> ColumnDef { /// Instantiate a new [ColumnDef]
fn def(self) -> ColumnDef;
/// Get the name of the enum if this is a enum column
fn get_enum_name(&self) -> Option<&DynIden>;
}
impl ColumnTypeTrait for ColumnType {
fn def(self) -> ColumnDef {
ColumnDef { ColumnDef {
col_type: self, col_type: self,
null: false, null: false,
@ -390,7 +299,7 @@ impl ColumnType {
} }
} }
pub(crate) fn get_enum_name(&self) -> Option<&DynIden> { fn get_enum_name(&self) -> Option<&DynIden> {
fn enum_name(col_type: &ColumnType) -> Option<&DynIden> { fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
match col_type { match col_type {
ColumnType::Enum { name, .. } => Some(name), ColumnType::Enum { name, .. } => Some(name),
@ -446,111 +355,6 @@ impl ColumnDef {
} }
} }
impl From<ColumnType> for sea_query::ColumnType {
fn from(column_type: ColumnType) -> Self {
fn convert_column_type(column_type: &ColumnType) -> sea_query::ColumnType {
match column_type {
ColumnType::Char(s) => sea_query::ColumnType::Char(*s),
ColumnType::String(s) => sea_query::ColumnType::String(*s),
ColumnType::Text => sea_query::ColumnType::Text,
ColumnType::TinyInteger => sea_query::ColumnType::TinyInteger,
ColumnType::SmallInteger => sea_query::ColumnType::SmallInteger,
ColumnType::Integer => sea_query::ColumnType::Integer,
ColumnType::BigInteger => sea_query::ColumnType::BigInteger,
ColumnType::TinyUnsigned => sea_query::ColumnType::TinyUnsigned,
ColumnType::SmallUnsigned => sea_query::ColumnType::SmallUnsigned,
ColumnType::Unsigned => sea_query::ColumnType::Unsigned,
ColumnType::BigUnsigned => sea_query::ColumnType::BigUnsigned,
ColumnType::Float => sea_query::ColumnType::Float,
ColumnType::Double => sea_query::ColumnType::Double,
ColumnType::Decimal(s) => sea_query::ColumnType::Decimal(*s),
ColumnType::DateTime => sea_query::ColumnType::DateTime,
ColumnType::Timestamp => sea_query::ColumnType::Timestamp,
ColumnType::TimestampWithTimeZone => sea_query::ColumnType::TimestampWithTimeZone,
ColumnType::Time => sea_query::ColumnType::Time,
ColumnType::Date => sea_query::ColumnType::Date,
ColumnType::Binary => {
sea_query::ColumnType::Binary(sea_query::BlobSize::Blob(None))
}
ColumnType::TinyBinary => sea_query::ColumnType::Binary(sea_query::BlobSize::Tiny),
ColumnType::MediumBinary => {
sea_query::ColumnType::Binary(sea_query::BlobSize::Medium)
}
ColumnType::LongBinary => sea_query::ColumnType::Binary(sea_query::BlobSize::Long),
ColumnType::Boolean => sea_query::ColumnType::Boolean,
ColumnType::Money(s) => sea_query::ColumnType::Money(*s),
ColumnType::Json => sea_query::ColumnType::Json,
ColumnType::JsonBinary => sea_query::ColumnType::JsonBinary,
ColumnType::Custom(s) => {
sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(s)))
}
ColumnType::Uuid => sea_query::ColumnType::Uuid,
ColumnType::Enum { name, variants } => sea_query::ColumnType::Enum {
name: SeaRc::clone(name),
variants: variants.clone(),
},
ColumnType::Array(column_type) => {
let column_type = convert_column_type(column_type);
sea_query::ColumnType::Array(SeaRc::new(column_type))
}
}
}
convert_column_type(&column_type)
}
}
impl From<sea_query::ColumnType> for ColumnType {
fn from(column_type: sea_query::ColumnType) -> Self {
#[allow(clippy::redundant_allocation)]
fn convert_column_type(column_type: &sea_query::ColumnType) -> ColumnType {
#[allow(unreachable_patterns)]
match column_type {
sea_query::ColumnType::Char(s) => ColumnType::Char(*s),
sea_query::ColumnType::String(s) => ColumnType::String(*s),
sea_query::ColumnType::Text => ColumnType::Text,
sea_query::ColumnType::TinyInteger => ColumnType::TinyInteger,
sea_query::ColumnType::SmallInteger => ColumnType::SmallInteger,
sea_query::ColumnType::Integer => ColumnType::Integer,
sea_query::ColumnType::BigInteger => ColumnType::BigInteger,
sea_query::ColumnType::TinyUnsigned => ColumnType::TinyUnsigned,
sea_query::ColumnType::SmallUnsigned => ColumnType::SmallUnsigned,
sea_query::ColumnType::Unsigned => ColumnType::Unsigned,
sea_query::ColumnType::BigUnsigned => ColumnType::BigUnsigned,
sea_query::ColumnType::Float => ColumnType::Float,
sea_query::ColumnType::Double => ColumnType::Double,
sea_query::ColumnType::Decimal(s) => ColumnType::Decimal(*s),
sea_query::ColumnType::DateTime => ColumnType::DateTime,
sea_query::ColumnType::Timestamp => ColumnType::Timestamp,
sea_query::ColumnType::TimestampWithTimeZone => ColumnType::TimestampWithTimeZone,
sea_query::ColumnType::Time => ColumnType::Time,
sea_query::ColumnType::Date => ColumnType::Date,
sea_query::ColumnType::Binary(sea_query::BlobSize::Blob(_)) => ColumnType::Binary,
sea_query::ColumnType::Binary(sea_query::BlobSize::Tiny) => ColumnType::TinyBinary,
sea_query::ColumnType::Binary(sea_query::BlobSize::Medium) => {
ColumnType::MediumBinary
}
sea_query::ColumnType::Binary(sea_query::BlobSize::Long) => ColumnType::LongBinary,
sea_query::ColumnType::Boolean => ColumnType::Boolean,
sea_query::ColumnType::Money(s) => ColumnType::Money(*s),
sea_query::ColumnType::Json => ColumnType::Json,
sea_query::ColumnType::JsonBinary => ColumnType::JsonBinary,
sea_query::ColumnType::Custom(s) => ColumnType::Custom(s.to_string()),
sea_query::ColumnType::Uuid => ColumnType::Uuid,
sea_query::ColumnType::Enum { name, variants } => ColumnType::Enum {
name: SeaRc::clone(name),
variants: variants.clone(),
},
sea_query::ColumnType::Array(column_type) => {
let column_type = convert_column_type(column_type);
ColumnType::Array(SeaRc::new(column_type))
}
_ => unimplemented!(),
}
}
convert_column_type(&column_type)
}
}
#[derive(Iden)] #[derive(Iden)]
struct Text; struct Text;

View File

@ -1,7 +1,7 @@
pub use crate::{ pub use crate::{
error::*, ActiveEnum, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, error::*, ActiveEnum, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait,
ColumnType, CursorTrait, DatabaseConnection, DbConn, EntityName, EntityTrait, EnumIter, ColumnType, ColumnTypeTrait, CursorTrait, DatabaseConnection, DbConn, EntityName, EntityTrait,
ForeignKeyAction, Iden, IdenStatic, Linked, LoaderTrait, ModelTrait, PaginatorTrait, EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, LoaderTrait, ModelTrait, PaginatorTrait,
PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef,
RelationTrait, Select, Value, RelationTrait, Select, Value,
}; };

View File

@ -4,7 +4,7 @@ use crate::{
}; };
use sea_query::{ use sea_query::{
extension::postgres::{Type, TypeCreateStatement}, extension::postgres::{Type, TypeCreateStatement},
ColumnDef, Iden, Index, IndexCreateStatement, TableCreateStatement, ColumnDef, Iden, Index, IndexCreateStatement, SeaRc, TableCreateStatement,
}; };
impl Schema { impl Schema {
@ -194,13 +194,12 @@ where
ColumnType::Enum { name, variants } => match backend { ColumnType::Enum { name, variants } => match backend {
DbBackend::MySql => { DbBackend::MySql => {
let variants: Vec<String> = variants.iter().map(|v| v.to_string()).collect(); let variants: Vec<String> = variants.iter().map(|v| v.to_string()).collect();
ColumnType::Custom(format!("ENUM('{}')", variants.join("', '"))) ColumnType::custom(format!("ENUM('{}')", variants.join("', '")).as_str())
} }
DbBackend::Postgres => ColumnType::Custom(name.to_string()), DbBackend::Postgres => ColumnType::Custom(SeaRc::clone(&name)),
DbBackend::Sqlite => ColumnType::Text, DbBackend::Sqlite => ColumnType::Text,
} },
.into(), _ => orm_column_def.col_type,
_ => orm_column_def.col_type.into(),
}; };
let mut column_def = ColumnDef::new_with_type(column, types); let mut column_def = ColumnDef::new_with_type(column, types);
if !orm_column_def.null { if !orm_column_def.null {

View File

@ -7,7 +7,7 @@ pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: i32, pub id: i32,
#[sea_orm( #[sea_orm(
column_type = r#"Custom("citext".into())"#, column_type = r#"custom("citext")"#,
select_as = "text", select_as = "text",
save_as = "citext" save_as = "citext"
)] )]