From 77bddd85a5f3916d898628d0192c9fade0fb88d8 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 22 Sep 2022 14:55:14 +0800 Subject: [PATCH] Fixup --- Cargo.toml | 8 +--- sea-orm-codegen/Cargo.toml | 5 +- sea-orm-codegen/src/entity/active_enum.rs | 11 +++-- sea-orm-codegen/src/entity/column.rs | 6 +-- sea-orm-codegen/src/entity/relation.rs | 3 +- sea-orm-codegen/src/entity/transformer.rs | 14 +++--- sea-orm-codegen/src/entity/writer.rs | 4 +- sea-orm-codegen/src/util.rs | 15 ++++++ sea-orm-macros/src/derives/active_enum.rs | 57 +++++++++++++++++++++-- src/driver/sqlx_sqlite.rs | 2 +- src/entity/active_enum.rs | 26 +++++++---- src/entity/column.rs | 44 ++++++++++++++--- src/executor/paginator.rs | 2 +- src/query/helper.rs | 2 +- src/schema/entity.rs | 21 ++++----- tests/common/features/schema.rs | 4 +- tests/common/setup/mod.rs | 8 ++-- 17 files changed, 165 insertions(+), 67 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5cfb4b0..fa32153f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ log = { version = "^0.4" } tracing = { version = "^0.1", features = ["log"] } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.10.0", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.27", features = ["thread-safe"] } -sea-query-binder = { version = "^0.1", optional = true } +sea-query = { version = "^0.27", git = "https://github.com/SeaQL/sea-query", features = ["thread-safe"] } +sea-query-binder = { version = "^0.1", git = "https://github.com/SeaQL/sea-query", optional = true } sea-strum = { version = "^0.23", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0", optional = true } @@ -45,10 +45,6 @@ ouroboros = "0.15" url = "^2.2" once_cell = "1.8" -[patch.crates-io] -sea-query = { git = "https://github.com/SeaQL/sea-query" } -sea-query-binder = { git = "https://github.com/SeaQL/sea-query" } - [dev-dependencies] smol = { version = "^1.2" } smol-potat = { version = "^1.1" } diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index f7984453..9dab2e7b 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -17,7 +17,7 @@ name = "sea_orm_codegen" path = "src/lib.rs" [dependencies] -sea-query = { version = "^0.27", features = ["thread-safe"] } +sea-query = { version = "^0.27", git = "https://github.com/SeaQL/sea-query", features = ["thread-safe"] } syn = { version = "^1", default-features = false, features = [ "derive", "parsing", @@ -31,6 +31,3 @@ tracing = { version = "0.1", features = ["log"] } [dev-dependencies] pretty_assertions = { version = "^0.7" } - -[patch.crates-io] -sea-query = { git = "https://github.com/SeaQL/sea-query" } diff --git a/sea-orm-codegen/src/entity/active_enum.rs b/sea-orm-codegen/src/entity/active_enum.rs index d4a7e600..c0d285f7 100644 --- a/sea-orm-codegen/src/entity/active_enum.rs +++ b/sea-orm-codegen/src/entity/active_enum.rs @@ -2,19 +2,20 @@ use crate::WithSerde; use heck::CamelCase; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use sea_query::DynIden; #[derive(Clone, Debug)] pub struct ActiveEnum { - pub(crate) enum_name: String, - pub(crate) values: Vec, + pub(crate) enum_name: DynIden, + pub(crate) values: Vec, } impl ActiveEnum { pub fn impl_active_enum(&self, with_serde: &WithSerde, with_copy_enums: bool) -> TokenStream { - let enum_name = &self.enum_name; + let enum_name = &self.enum_name.to_string(); let enum_iden = format_ident!("{}", enum_name.to_camel_case()); - let values = &self.values; - let variants = self.values.iter().map(|v| v.trim()).map(|v| { + let values: Vec = self.values.iter().map(|v| v.to_string()).collect(); + let variants = values.iter().map(|v| v.trim()).map(|v| { if v.chars().all(|c| c.is_numeric()) { format_ident!("_{}", v) } else { diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index 2060853e..3c4d739c 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -70,7 +70,7 @@ impl Column { ColumnType::Uuid => "Uuid".to_owned(), ColumnType::Binary(_) | ColumnType::VarBinary(_) => "Vec".to_owned(), ColumnType::Boolean => "bool".to_owned(), - ColumnType::Enum(name, _) => name.to_camel_case(), + ColumnType::Enum { name, .. } => name.to_string().to_camel_case(), _ => unimplemented!(), } .parse() @@ -146,8 +146,8 @@ impl Column { let s = s.to_string(); quote! { ColumnType::Custom(#s.to_owned()).def() } } - ColumnType::Enum(enum_name, _) => { - let enum_ident = format_ident!("{}", enum_name.to_camel_case()); + ColumnType::Enum { name, .. } => { + let enum_ident = format_ident!("{}", name.to_string().to_camel_case()); quote! { #enum_ident::db_type() } } #[allow(unreachable_patterns)] diff --git a/sea-orm-codegen/src/entity/relation.rs b/sea-orm-codegen/src/entity/relation.rs index 57722e50..185af317 100644 --- a/sea-orm-codegen/src/entity/relation.rs +++ b/sea-orm-codegen/src/entity/relation.rs @@ -1,3 +1,4 @@ +use crate::util::unpack_table_ref; use heck::{CamelCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; @@ -155,7 +156,7 @@ impl Relation { impl From<&TableForeignKey> for Relation { fn from(tbl_fk: &TableForeignKey) -> Self { let ref_table = match tbl_fk.get_ref_table() { - Some(s) => s, + Some(s) => unpack_table_ref(s), None => panic!("RefTable should not be empty"), }; let columns = tbl_fk.get_columns(); diff --git a/sea-orm-codegen/src/entity/transformer.rs b/sea-orm-codegen/src/entity/transformer.rs index 43cc111b..0c0da7d5 100644 --- a/sea-orm-codegen/src/entity/transformer.rs +++ b/sea-orm-codegen/src/entity/transformer.rs @@ -1,6 +1,6 @@ use crate::{ - ActiveEnum, Column, ConjunctRelation, Entity, EntityWriter, Error, PrimaryKey, Relation, - RelationType, + util::unpack_table_ref, ActiveEnum, Column, ConjunctRelation, Entity, EntityWriter, Error, + PrimaryKey, Relation, RelationType, }; use sea_query::{ColumnSpec, TableCreateStatement}; use std::collections::HashMap; @@ -59,12 +59,12 @@ impl EntityTransformer { col }) .map(|col| { - if let sea_query::ColumnType::Enum(enum_name, values) = &col.col_type { + if let sea_query::ColumnType::Enum { name, variants } = &col.col_type { enums.insert( - enum_name.clone(), + name.to_string(), ActiveEnum { - enum_name: enum_name.clone(), - values: values.clone(), + enum_name: name.clone(), + values: variants.clone(), }, ); } @@ -77,7 +77,7 @@ impl EntityTransformer { .iter() .map(|fk_create_stmt| fk_create_stmt.get_foreign_key()) .map(|tbl_fk| { - let ref_tbl = tbl_fk.get_ref_table().unwrap(); + let ref_tbl = unpack_table_ref(tbl_fk.get_ref_table().unwrap()); if let Some(count) = ref_table_counts.get_mut(&ref_tbl) { if *count == 0 { *count = 1; diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index 19722e18..2d7bc87c 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -363,8 +363,8 @@ impl EntityWriter { .columns .iter() .fold(TokenStream::new(), |mut ts, col| { - if let sea_query::ColumnType::Enum(enum_name, _) = &col.col_type { - let enum_name = format_ident!("{}", enum_name.to_camel_case()); + if let sea_query::ColumnType::Enum { name, .. } = &col.col_type { + let enum_name = format_ident!("{}", name.to_string().to_camel_case()); ts.extend(vec![quote! { use super::sea_orm_active_enums::#enum_name; }]); diff --git a/sea-orm-codegen/src/util.rs b/sea-orm-codegen/src/util.rs index 34c46c54..5d74f3d4 100644 --- a/sea-orm-codegen/src/util.rs +++ b/sea-orm-codegen/src/util.rs @@ -1,3 +1,5 @@ +use sea_query::TableRef; + pub(crate) fn escape_rust_keyword(string: T) -> String where T: ToString, @@ -21,3 +23,16 @@ pub(crate) const RUST_KEYWORDS: [&str; 49] = [ ]; pub(crate) const RUST_SPECIAL_KEYWORDS: [&str; 3] = ["crate", "Self", "self"]; + +pub(crate) fn unpack_table_ref(table_ref: &TableRef) -> String { + match table_ref { + TableRef::Table(tbl) + | TableRef::SchemaTable(_, tbl) + | TableRef::DatabaseSchemaTable(_, _, tbl) + | TableRef::TableAlias(tbl, _) + | TableRef::SchemaTableAlias(_, tbl, _) + | TableRef::DatabaseSchemaTableAlias(_, _, tbl, _) + | TableRef::SubQuery(_, tbl) + | TableRef::ValuesList(_, tbl) => tbl.to_string(), + } +} diff --git a/sea-orm-macros/src/derives/active_enum.rs b/sea-orm-macros/src/derives/active_enum.rs index cbc9c4b0..c7693ae3 100644 --- a/sea-orm-macros/src/derives/active_enum.rs +++ b/sea-orm-macros/src/derives/active_enum.rs @@ -1,6 +1,6 @@ use heck::CamelCase; use proc_macro2::TokenStream; -use quote::{quote, quote_spanned}; +use quote::{format_ident, quote, quote_spanned}; use syn::{parse, punctuated::Punctuated, token::Comma, Expr, Lit, LitInt, LitStr, Meta, UnOp}; enum Error { @@ -59,7 +59,10 @@ impl ActiveEnum { match s.as_ref() { "Enum" => { db_type = Ok(quote! { - Enum(Self::name(), Self::values()) + Enum { + name: Self::name(), + variants: Self::iden_values(), + } }) } _ => { @@ -227,13 +230,59 @@ impl ActiveEnum { quote! { v } }; + let enum_name_iden = format_ident!("{}Enum", ident); + + let str_variants: Vec = variants + .iter() + .filter_map(|variant| { + variant + .string_value + .as_ref() + .map(|string_value| string_value.value()) + }) + .collect(); + + let impl_enum_variant_iden = if !str_variants.is_empty() { + let enum_variant_iden = format_ident!("{}Variant", ident); + let enum_variants: Vec = str_variants + .iter() + .map(|v| format_ident!("{}", v.to_camel_case())) + .collect(); + + quote!( + #[derive(Debug, Clone, PartialEq, Eq, EnumIter, Iden)] + pub enum #enum_variant_iden { + #( + #[iden = #str_variants] + #enum_variants, + )* + } + + impl #ident { + pub fn iden_values() -> Vec { + <#enum_variant_iden as sea_orm::strum::IntoEnumIterator>::iter() + .map(|v| sea_orm::sea_query::SeaRc::new(v) as sea_orm::sea_query::DynIden) + .collect() + } + } + ) + } else { + quote!() + }; + quote!( + #[derive(Debug, Clone, PartialEq, Eq, Iden)] + #[iden = #enum_name] + pub struct #enum_name_iden; + + #impl_enum_variant_iden + #[automatically_derived] impl sea_orm::ActiveEnum for #ident { type Value = #rs_type; - fn name() -> String { - #enum_name.to_owned() + fn name() -> sea_orm::sea_query::DynIden { + sea_orm::sea_query::SeaRc::new(#enum_name_iden) as sea_orm::sea_query::DynIden } fn to_value(&self) -> Self::Value { diff --git a/src/driver/sqlx_sqlite.rs b/src/driver/sqlx_sqlite.rs index 3898661a..2d3a4814 100644 --- a/src/driver/sqlx_sqlite.rs +++ b/src/driver/sqlx_sqlite.rs @@ -2,7 +2,7 @@ use sea_query::Values; use std::{future::Future, pin::Pin, sync::Arc}; use sqlx::{ - sqlite::{SqliteArguments, SqliteConnectOptions, SqliteQueryResult, SqliteRow}, + sqlite::{SqliteConnectOptions, SqliteQueryResult, SqliteRow}, Sqlite, SqlitePool, }; diff --git a/src/entity/active_enum.rs b/src/entity/active_enum.rs index 2e03d4fd..86bd126b 100644 --- a/src/entity/active_enum.rs +++ b/src/entity/active_enum.rs @@ -1,5 +1,5 @@ use crate::{ColumnDef, DbErr, Iterable, TryGetable}; -use sea_query::{Nullable, Value, ValueType}; +use sea_query::{DynIden, Nullable, Value, ValueType}; /// A Rust representation of enum defined in database. /// @@ -37,13 +37,16 @@ use sea_query::{Nullable, Value, ValueType}; /// Small, /// } /// +/// #[derive(Debug, Iden)] +/// pub struct CategoryEnum; +/// /// impl ActiveEnum for Category { /// // The macro attribute `rs_type` is being pasted here /// type Value = String; /// /// // Will be atomically generated by `DeriveActiveEnum` -/// fn name() -> String { -/// "category".to_owned() +/// fn name() -> DynIden { +/// SeaRc::new(CategoryEnum) /// } /// /// // Will be atomically generated by `DeriveActiveEnum` @@ -109,7 +112,7 @@ pub trait ActiveEnum: Sized + Iterable { type Value: Into + ValueType + Nullable + TryGetable; /// Get the name of enum - fn name() -> String; + fn name() -> DynIden; /// Convert enum variant into the corresponding value. fn to_value(&self) -> Self::Value; @@ -134,7 +137,7 @@ pub trait ActiveEnum: Sized + Iterable { #[cfg(test)] mod tests { use crate as sea_orm; - use crate::{entity::prelude::*, *}; + use crate::{entity::prelude::*, sea_query::SeaRc, *}; use pretty_assertions::assert_eq; #[test] @@ -145,11 +148,15 @@ mod tests { Small, } + #[derive(Debug, Iden)] + #[iden = "category"] + pub struct CategoryEnum; + impl ActiveEnum for Category { type Value = String; - fn name() -> String { - "category".to_owned() + fn name() -> DynIden { + SeaRc::new(CategoryEnum) } fn to_value(&self) -> Self::Value { @@ -226,7 +233,10 @@ mod tests { assert_eq!(Category::db_type(), ColumnType::String(Some(1)).def()); assert_eq!(DeriveCategory::db_type(), ColumnType::String(Some(1)).def()); - assert_eq!(Category::name(), DeriveCategory::name()); + assert_eq!( + Category::name().to_string(), + DeriveCategory::name().to_string() + ); assert_eq!(Category::values(), DeriveCategory::values()); } diff --git a/src/entity/column.rs b/src/entity/column.rs index 92e32fb6..802a3de2 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -13,7 +13,7 @@ pub struct ColumnDef { } /// The type of column as defined in the SQL format -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum ColumnType { /// `CHAR` type of specified fixed length Char(Option), @@ -78,7 +78,39 @@ pub enum ColumnType { /// A Universally Unique IDentifier that is specified in RFC 4122 Uuid, /// `ENUM` data type with name and variants - Enum(String, Vec), + Enum { + /// Name of enum + name: DynIden, + /// Variants of enum + variants: Vec, + }, +} + +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::>() + == r_variants.iter().map(|v| v.to_string()).collect::>() + } + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } } macro_rules! bind_oper { @@ -318,9 +350,9 @@ impl ColumnType { } } - pub(crate) fn get_enum_name(&self) -> Option<&String> { + pub(crate) fn get_enum_name(&self) -> Option<&DynIden> { match self { - ColumnType::Enum(s, _) => Some(s), + ColumnType::Enum { name, .. } => Some(name), _ => None, } } @@ -399,7 +431,7 @@ impl From for sea_query::ColumnType { 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, variants), + ColumnType::Enum { name, variants } => sea_query::ColumnType::Enum { name, variants }, } } } @@ -437,7 +469,7 @@ impl From for ColumnType { sea_query::ColumnType::JsonBinary => Self::JsonBinary, sea_query::ColumnType::Custom(s) => Self::Custom(s.to_string()), sea_query::ColumnType::Uuid => Self::Uuid, - sea_query::ColumnType::Enum(name, variants) => Self::Enum(name, variants), + sea_query::ColumnType::Enum { name, variants } => Self::Enum { name, variants }, _ => unimplemented!(), } } diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs index a296efa5..d3f3e8b5 100644 --- a/src/executor/paginator.rs +++ b/src/executor/paginator.rs @@ -251,7 +251,7 @@ where { type Selector = S; fn paginate(self, db: &'db C, page_size: u64) -> Paginator<'db, C, S> { - let sql = &self.stmt.sql[6..]; + let sql = &self.stmt.sql[7..]; let mut query = SelectStatement::new(); query.expr(if let Some(values) = self.stmt.values { Expr::cust_with_values(sql, values.0) diff --git a/src/query/helper.rs b/src/query/helper.rs index f476d60c..89dd61f1 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -581,7 +581,7 @@ where let col_def = col.def(); let col_type = col_def.get_column_type(); match col_type.get_enum_name() { - Some(enum_name) => f(expr, SeaRc::new(Alias::new(enum_name))), + Some(enum_name) => f(expr, SeaRc::clone(enum_name)), None => expr.into(), } } diff --git a/src/schema/entity.rs b/src/schema/entity.rs index c09862be..089a4fe5 100644 --- a/src/schema/entity.rs +++ b/src/schema/entity.rs @@ -1,11 +1,10 @@ use crate::{ - unpack_table_ref, ActiveEnum, ColumnTrait, ColumnType, DbBackend, EntityTrait, Identity, - Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, RelationTrait, Schema, + unpack_table_ref, ActiveEnum, ColumnDef, ColumnTrait, ColumnType, DbBackend, EntityTrait, + Identity, Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, RelationTrait, Schema, }; use sea_query::{ extension::postgres::{Type, TypeCreateStatement}, - Alias, ColumnDef, ForeignKeyCreateStatement, Iden, Index, IndexCreateStatement, - TableCreateStatement, + ForeignKeyCreateStatement, Iden, Index, IndexCreateStatement, TableCreateStatement, }; impl Schema { @@ -57,13 +56,10 @@ where pub(crate) fn create_enum_from_column_type(col_type: &ColumnType) -> TypeCreateStatement { let (name, values) = match col_type { - ColumnType::Enum(s, v) => (s.as_str(), v), + ColumnType::Enum { name, variants } => (name.clone(), variants.clone()), _ => panic!("Should be ColumnType::Enum"), }; - Type::create() - .as_enum(Alias::new(name)) - .values(values.iter().map(|val| Alias::new(val.as_str()))) - .to_owned() + Type::create().as_enum(name).values(values).to_owned() } #[allow(clippy::needless_borrow)] @@ -78,7 +74,7 @@ where for col in E::Column::iter() { let col_def = col.def(); let col_type = col_def.get_column_type(); - if !matches!(col_type, ColumnType::Enum(_, _)) { + if !matches!(col_type, ColumnType::Enum { .. }) { continue; } let stmt = create_enum_from_column_type(&col_type); @@ -123,11 +119,12 @@ where for column in E::Column::iter() { let orm_column_def = column.def(); let types = match orm_column_def.col_type { - ColumnType::Enum(s, variants) => match backend { + ColumnType::Enum { name, variants } => match backend { DbBackend::MySql => { + let variants: Vec = variants.iter().map(|v| v.to_string()).collect(); ColumnType::Custom(format!("ENUM('{}')", variants.join("', '"))) } - DbBackend::Postgres => ColumnType::Custom(s), + DbBackend::Postgres => ColumnType::Custom(name.to_string()), DbBackend::Sqlite => ColumnType::Text, } .into(), diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs index b6bf9ae4..f14568bc 100644 --- a/tests/common/features/schema.rs +++ b/tests/common/features/schema.rs @@ -166,7 +166,7 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result .col(ColumnDef::new(active_enum::Column::Color).integer()) .col( ColumnDef::new(active_enum::Column::Tea) - .enumeration("tea", vec!["EverydayTea", "BreakfastTea"]), + .enumeration(TeaEnum, [TeaVariant::EverydayTea, TeaVariant::BreakfastTea]), ) .to_owned(); @@ -192,7 +192,7 @@ pub async fn create_active_enum_child_table(db: &DbConn) -> Result DatabaseConnection { @@ -88,15 +88,15 @@ where for col in E::Column::iter() { let col_def = col.def(); let col_type = col_def.get_column_type(); - if !matches!(col_type, ColumnType::Enum(_, _)) { + if !matches!(col_type, ColumnType::Enum { .. }) { continue; } let name = match col_type { - ColumnType::Enum(s, _) => s.as_str(), + ColumnType::Enum { name, .. } => name, _ => unreachable!(), }; let drop_type_stmt = Type::drop() - .name(Alias::new(name)) + .name(SeaRc::clone(name)) .if_exists() .cascade() .to_owned();