From 734608471c2b14c96bda1e61df84fb83b2ee539f Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Wed, 20 Oct 2021 18:54:08 +0800
Subject: [PATCH 01/16] WIP

---
 src/entity/active_enum.rs            | 18 +++++++++---------
 src/entity/column.rs                 |  4 ++++
 tests/active_enum_tests.rs           |  8 ++++----
 tests/common/features/active_enum.rs | 10 +++++-----
 4 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/src/entity/active_enum.rs b/src/entity/active_enum.rs
index 5eb77b9f2b..edca0aac1e 100644
--- a/src/entity/active_enum.rs
+++ b/src/entity/active_enum.rs
@@ -1,4 +1,4 @@
-use crate::{ColumnDef, DbErr, TryGetable};
+use crate::{ColumnDef, DbErr, Iterable, TryGetable};
 use sea_query::{Nullable, Value, ValueType};
 
 /// A Rust representation of enum defined in database.
@@ -17,7 +17,7 @@ use sea_query::{Nullable, Value, ValueType};
 /// use sea_orm::entity::prelude::*;
 ///
 /// // Using the derive macro
-/// #[derive(Debug, PartialEq, DeriveActiveEnum)]
+/// #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
 /// #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
 /// pub enum DeriveCategory {
 ///     #[sea_orm(string_value = "B")]
@@ -27,7 +27,7 @@ use sea_query::{Nullable, Value, ValueType};
 /// }
 ///
 /// // Implementing it manually
-/// #[derive(Debug, PartialEq)]
+/// #[derive(Debug, PartialEq, EnumIter)]
 /// pub enum Category {
 ///     Big,
 ///     Small,
@@ -80,7 +80,7 @@ use sea_query::{Nullable, Value, ValueType};
 ///     Small,
 /// }
 ///
-/// #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
+/// #[derive(Clone, Debug, PartialEq, EnumIter, DeriveEntityModel)]
 /// #[sea_orm(table_name = "active_enum")]
 /// pub struct Model {
 ///     #[sea_orm(primary_key)]
@@ -95,7 +95,7 @@ use sea_query::{Nullable, Value, ValueType};
 ///
 /// impl ActiveModelBehavior for ActiveModel {}
 /// ```
-pub trait ActiveEnum: Sized {
+pub trait ActiveEnum: Sized + Iterable {
     /// Define the Rust type that each enum variant represents.
     type Value: Into<Value> + ValueType + Nullable + TryGetable;
 
@@ -117,7 +117,7 @@ mod tests {
 
     #[test]
     fn active_enum_string() {
-        #[derive(Debug, PartialEq)]
+        #[derive(Debug, PartialEq, EnumIter)]
         pub enum Category {
             Big,
             Small,
@@ -150,7 +150,7 @@ mod tests {
             }
         }
 
-        #[derive(Debug, PartialEq, DeriveActiveEnum)]
+        #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
         #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
         pub enum DeriveCategory {
             #[sea_orm(string_value = "B")]
@@ -201,7 +201,7 @@ mod tests {
     fn active_enum_derive_signed_integers() {
         macro_rules! test_int {
             ($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
-                #[derive(Debug, PartialEq, DeriveActiveEnum)]
+                #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
                 #[sea_orm(rs_type = $rs_type, db_type = $db_type)]
                 pub enum $ident {
                     #[sea_orm(num_value = 1)]
@@ -241,7 +241,7 @@ mod tests {
     fn active_enum_derive_unsigned_integers() {
         macro_rules! test_uint {
             ($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
-                #[derive(Debug, PartialEq, DeriveActiveEnum)]
+                #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
                 #[sea_orm(rs_type = $rs_type, db_type = $db_type)]
                 pub enum $ident {
                     #[sea_orm(num_value = 1)]
diff --git a/src/entity/column.rs b/src/entity/column.rs
index 25ed844731..384be24a0d 100644
--- a/src/entity/column.rs
+++ b/src/entity/column.rs
@@ -34,6 +34,7 @@ pub enum ColumnType {
     JsonBinary,
     Custom(String),
     Uuid,
+    Enum(String),
 }
 
 macro_rules! bind_oper {
@@ -295,6 +296,9 @@ impl From<ColumnType> 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(s) => {
+                sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s)))
+            }
         }
     }
 }
diff --git a/tests/active_enum_tests.rs b/tests/active_enum_tests.rs
index 5685248145..b0c72a8229 100644
--- a/tests/active_enum_tests.rs
+++ b/tests/active_enum_tests.rs
@@ -24,7 +24,7 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
     let am = ActiveModel {
         category: Set(None),
         color: Set(None),
-        // tea: Set(None),
+        tea: Set(None),
         ..Default::default()
     }
     .insert(db)
@@ -36,14 +36,14 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
             id: 1,
             category: None,
             color: None,
-            // tea: None,
+            tea: None,
         }
     );
 
     ActiveModel {
         category: Set(Some(Category::Big)),
         color: Set(Some(Color::Black)),
-        // tea: Set(Some(Tea::EverydayTea)),
+        tea: Set(Some(Tea::EverydayTea)),
         ..am
     }
     .save(db)
@@ -55,7 +55,7 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
             id: 1,
             category: Some(Category::Big),
             color: Some(Color::Black),
-            // tea: Some(Tea::EverydayTea),
+            tea: Some(Tea::EverydayTea),
         }
     );
 
diff --git a/tests/common/features/active_enum.rs b/tests/common/features/active_enum.rs
index d7b15443e7..229d44466f 100644
--- a/tests/common/features/active_enum.rs
+++ b/tests/common/features/active_enum.rs
@@ -7,7 +7,7 @@ pub struct Model {
     pub id: i32,
     pub category: Option<Category>,
     pub color: Option<Color>,
-    // pub tea: Option<Tea>,
+    pub tea: Option<Tea>,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
@@ -15,7 +15,7 @@ pub enum Relation {}
 
 impl ActiveModelBehavior for ActiveModel {}
 
-#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
 pub enum Category {
     #[sea_orm(string_value = "B")]
@@ -24,7 +24,7 @@ pub enum Category {
     Small,
 }
 
-#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
 #[sea_orm(rs_type = "i32", db_type = r#"Integer"#)]
 pub enum Color {
     #[sea_orm(num_value = 0)]
@@ -33,8 +33,8 @@ pub enum Color {
     White,
 }
 
-#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
-#[sea_orm(rs_type = "String", db_type = r#"Custom("tea".to_owned())"#)]
+#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
+#[sea_orm(rs_type = "String", db_type = r#"Enum("tea".to_owned())"#)]
 pub enum Tea {
     #[sea_orm(string_value = "EverydayTea")]
     EverydayTea,

From 80c72004d15afa8c4e6920abab76e91d55f5161a Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Thu, 21 Oct 2021 15:40:22 +0800
Subject: [PATCH 02/16] Try Postgres enum

---
 Cargo.toml                      |  2 +-
 src/entity/active_enum.rs       |  2 +-
 src/entity/column.rs            |  7 ++++++
 src/query/insert.rs             | 19 +++++++++++----
 src/query/select.rs             | 20 ++++++++++++---
 src/query/update.rs             | 12 +++++++--
 tests/active_enum_tests.rs      |  7 +++++-
 tests/common/features/schema.rs | 43 +++++++++++++++++++++++++++++++--
 8 files changed, 96 insertions(+), 16 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 7169037488..42f97b62eb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,7 +30,7 @@ futures-util = { version = "^0.3" }
 log = { version = "^0.4", optional = true }
 rust_decimal = { version = "^1", optional = true }
 sea-orm-macros = { version = "^0.3.0", path = "sea-orm-macros", optional = true }
-sea-query = { version = "^0.18.0", features = ["thread-safe"] }
+sea-query = { version = "^0.18.0", git = "https://github.com/SeaQL/sea-query.git", branch = "sea-orm/active-enum-1", features = ["thread-safe"] }
 sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] }
 serde = { version = "^1.0", features = ["derive"] }
 serde_json = { version = "^1", optional = true }
diff --git a/src/entity/active_enum.rs b/src/entity/active_enum.rs
index edca0aac1e..b42b31f7b3 100644
--- a/src/entity/active_enum.rs
+++ b/src/entity/active_enum.rs
@@ -71,7 +71,7 @@ use sea_query::{Nullable, Value, ValueType};
 /// use sea_orm::entity::prelude::*;
 ///
 /// // Define the `Category` active enum
-/// #[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
+/// #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
 /// #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
 /// pub enum Category {
 ///     #[sea_orm(string_value = "B")]
diff --git a/src/entity/column.rs b/src/entity/column.rs
index 384be24a0d..32fe030c6d 100644
--- a/src/entity/column.rs
+++ b/src/entity/column.rs
@@ -242,6 +242,13 @@ impl ColumnType {
             indexed: false,
         }
     }
+
+    pub(crate) fn get_enum_name(&self) -> Option<&String> {
+        match self {
+            ColumnType::Enum(s) => Some(s),
+            _ => None,
+        }
+    }
 }
 
 impl ColumnDef {
diff --git a/src/query/insert.rs b/src/query/insert.rs
index 5e504a0c5a..f7f7c7d385 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -1,9 +1,9 @@
 use crate::{
-    ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait,
-    QueryTrait,
+    ActiveModelTrait, ColumnTrait, EntityName, EntityTrait, IntoActiveModel, Iterable,
+    PrimaryKeyTrait, QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{InsertStatement, ValueTuple};
+use sea_query::{Alias, Expr, Func, InsertStatement, ValueTuple};
 
 #[derive(Debug)]
 pub struct Insert<A>
@@ -124,6 +124,9 @@ where
         for (idx, col) in <A::Entity as EntityTrait>::Column::iter().enumerate() {
             let av = am.take(col);
             let av_has_val = av.is_set() || av.is_unchanged();
+            let col_def = col.def();
+            let enum_name = col_def.get_column_type().get_enum_name();
+
             if columns_empty {
                 self.columns.push(av_has_val);
             } else if self.columns[idx] != av_has_val {
@@ -131,11 +134,17 @@ where
             }
             if av_has_val {
                 columns.push(col);
-                values.push(av.into_value().unwrap());
+                let val = av.into_value().unwrap();
+                let expr = if let Some(enum_name) = enum_name {
+                    Func::cast_as(val, Alias::new(&enum_name))
+                } else {
+                    Expr::val(val).into()
+                };
+                values.push(expr);
             }
         }
         self.query.columns(columns);
-        self.query.values_panic(values);
+        self.query.exprs_panic(values);
         self
     }
 
diff --git a/src/query/select.rs b/src/query/select.rs
index 1b0c93c3d7..5a2e0cdc21 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -2,7 +2,7 @@ use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySe
 use core::fmt::Debug;
 use core::marker::PhantomData;
 pub use sea_query::JoinType;
-use sea_query::{DynIden, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
+use sea_query::{Alias, DynIden, Expr, Func, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
 
 #[derive(Clone, Debug)]
 pub struct Select<E>
@@ -109,13 +109,25 @@ where
     }
 
     fn prepare_select(mut self) -> Self {
-        self.query.columns(self.column_list());
+        self.query.exprs(self.column_list());
         self
     }
 
-    fn column_list(&self) -> Vec<(DynIden, E::Column)> {
+    fn column_list(&self) -> Vec<SimpleExpr> {
         let table = SeaRc::new(E::default()) as DynIden;
-        E::Column::iter().map(|col| (table.clone(), col)).collect()
+        E::Column::iter()
+            .map(|col| {
+                let col_def = col.def();
+                let enum_name = col_def.get_column_type().get_enum_name();
+                let col_expr = Expr::tbl(table.clone(), col);
+                let col_expr = if let Some(_) = enum_name {
+                    Func::cast_expr_as(col_expr, Alias::new("text"))
+                } else {
+                    col_expr.into()
+                };
+                col_expr
+            })
+            .collect()
     }
 
     fn prepare_from(mut self) -> Self {
diff --git a/src/query/update.rs b/src/query/update.rs
index fec7757cc2..2f9bdb3bcd 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -3,7 +3,7 @@ use crate::{
     QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{IntoIden, SimpleExpr, UpdateStatement};
+use sea_query::{Alias, Expr, Func, IntoIden, SimpleExpr, UpdateStatement};
 
 #[derive(Clone, Debug)]
 pub struct Update;
@@ -104,9 +104,17 @@ where
             if <A::Entity as EntityTrait>::PrimaryKey::from_column(col).is_some() {
                 continue;
             }
+            let col_def = col.def();
+            let enum_name = col_def.get_column_type().get_enum_name();
             let av = self.model.get(col);
             if av.is_set() {
-                self.query.value(col, av.unwrap());
+                let val = av.into_value().unwrap();
+                let expr = if let Some(enum_name) = enum_name {
+                    Func::cast_as(val, Alias::new(&enum_name))
+                } else {
+                    Expr::val(val).into()
+                };
+                self.query.value_expr(col, expr);
             }
         }
         self
diff --git a/tests/active_enum_tests.rs b/tests/active_enum_tests.rs
index b0c72a8229..ca9bf7d995 100644
--- a/tests/active_enum_tests.rs
+++ b/tests/active_enum_tests.rs
@@ -40,7 +40,7 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
         }
     );
 
-    ActiveModel {
+    let am = ActiveModel {
         category: Set(Some(Category::Big)),
         color: Set(Some(Color::Black)),
         tea: Set(Some(Tea::EverydayTea)),
@@ -59,5 +59,10 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
         }
     );
 
+    let res = am.delete(db).await?;
+
+    assert_eq!(res.rows_affected, 1);
+    assert_eq!(Entity::find().one(db).await?, None);
+
     Ok(())
 }
diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs
index 823ccdfd9f..ffb47f2692 100644
--- a/tests/common/features/schema.rs
+++ b/tests/common/features/schema.rs
@@ -3,7 +3,7 @@ pub use super::super::bakery_chain::*;
 use super::*;
 use crate::common::setup::create_table;
 use sea_orm::{error::*, sea_query, DatabaseConnection, DbConn, ExecResult};
-use sea_query::{ColumnDef, ForeignKeyCreateStatement};
+use sea_query::{Alias, ColumnDef, ForeignKeyCreateStatement};
 
 pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> {
     create_log_table(db).await?;
@@ -103,6 +103,8 @@ pub async fn create_self_join_table(db: &DbConn) -> Result<ExecResult, DbErr> {
 }
 
 pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr> {
+    let tea_enum = Alias::new("tea");
+
     let stmt = sea_query::Table::create()
         .table(active_enum::Entity)
         .col(
@@ -114,8 +116,45 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
         )
         .col(ColumnDef::new(active_enum::Column::Category).string_len(1))
         .col(ColumnDef::new(active_enum::Column::Color).integer())
-        // .col(ColumnDef::new(active_enum::Column::Tea).custom(Alias::new("tea")))
+        .col(ColumnDef::new(active_enum::Column::Tea).custom(tea_enum.clone()))
         .to_owned();
 
+    match db {
+        #[cfg(feature = "sqlx-postgres")]
+        DatabaseConnection::SqlxPostgresPoolConnection(_) => {
+            use sea_orm::{ConnectionTrait, Statement};
+            use sea_query::{extension::postgres::Type, PostgresQueryBuilder};
+
+            let drop_type_stmt = Type::drop()
+                .name(tea_enum.clone())
+                .cascade()
+                .if_exists()
+                .to_owned();
+            let (sql, values) = drop_type_stmt.build(PostgresQueryBuilder);
+            let stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
+            db.execute(stmt).await?;
+
+            let create_type_stmt = Type::create()
+                .as_enum(tea_enum)
+                .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")])
+                .to_owned();
+
+            // FIXME: This is not working
+            {
+                let (sql, values) = create_type_stmt.build(PostgresQueryBuilder);
+                let _stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
+            }
+
+            // But this is working...
+            let stmt = Statement::from_string(
+                db.get_database_backend(),
+                create_type_stmt.to_string(PostgresQueryBuilder),
+            );
+
+            db.execute(stmt).await?;
+        }
+        _ => {}
+    }
+
     create_table(db, &stmt, ActiveEnum).await
 }

From 20c66b2f059824a2148c2b9fd064cf9dc5c956af Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Thu, 21 Oct 2021 15:50:18 +0800
Subject: [PATCH 03/16] Refactoring

---
 src/query/insert.rs | 2 +-
 src/query/select.rs | 5 ++---
 src/query/update.rs | 2 +-
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/query/insert.rs b/src/query/insert.rs
index f7f7c7d385..3a7c91d67e 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -136,7 +136,7 @@ where
                 columns.push(col);
                 let val = av.into_value().unwrap();
                 let expr = if let Some(enum_name) = enum_name {
-                    Func::cast_as(val, Alias::new(&enum_name))
+                    Func::cast_as(val, Alias::new(enum_name))
                 } else {
                     Expr::val(val).into()
                 };
diff --git a/src/query/select.rs b/src/query/select.rs
index 5a2e0cdc21..0f2db65bf8 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -120,12 +120,11 @@ where
                 let col_def = col.def();
                 let enum_name = col_def.get_column_type().get_enum_name();
                 let col_expr = Expr::tbl(table.clone(), col);
-                let col_expr = if let Some(_) = enum_name {
+                if enum_name.is_some() {
                     Func::cast_expr_as(col_expr, Alias::new("text"))
                 } else {
                     col_expr.into()
-                };
-                col_expr
+                }
             })
             .collect()
     }
diff --git a/src/query/update.rs b/src/query/update.rs
index 2f9bdb3bcd..a881ad1154 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -110,7 +110,7 @@ where
             if av.is_set() {
                 let val = av.into_value().unwrap();
                 let expr = if let Some(enum_name) = enum_name {
-                    Func::cast_as(val, Alias::new(&enum_name))
+                    Func::cast_as(val, Alias::new(enum_name))
                 } else {
                     Expr::val(val).into()
                 };

From 1ee2dab3b7df2f57b684a16ebc9d39d5b4344b33 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Thu, 21 Oct 2021 15:53:46 +0800
Subject: [PATCH 04/16] Fixup

---
 src/entity/active_enum.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/entity/active_enum.rs b/src/entity/active_enum.rs
index b42b31f7b3..230ee8f2ab 100644
--- a/src/entity/active_enum.rs
+++ b/src/entity/active_enum.rs
@@ -80,7 +80,7 @@ use sea_query::{Nullable, Value, ValueType};
 ///     Small,
 /// }
 ///
-/// #[derive(Clone, Debug, PartialEq, EnumIter, DeriveEntityModel)]
+/// #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
 /// #[sea_orm(table_name = "active_enum")]
 /// pub struct Model {
 ///     #[sea_orm(primary_key)]

From 8858d64dd0641cc0ef28a3969711ceae79e9f138 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Mon, 25 Oct 2021 15:48:01 +0800
Subject: [PATCH 05/16] create_table_from_entity with DB backend

---
 src/schema/entity.rs      | 17 ++++++++++-------
 tests/common/setup/mod.rs |  5 ++++-
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/schema/entity.rs b/src/schema/entity.rs
index a95b704781..2d0aa13a1a 100644
--- a/src/schema/entity.rs
+++ b/src/schema/entity.rs
@@ -1,19 +1,19 @@
 use crate::{
-    unpack_table_ref, ColumnTrait, EntityTrait, Identity, Iterable, PrimaryKeyToColumn,
+    unpack_table_ref, ColumnTrait, DbBackend, EntityTrait, Identity, Iterable, PrimaryKeyToColumn,
     PrimaryKeyTrait, RelationTrait, Schema,
 };
 use sea_query::{ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement};
 
 impl Schema {
-    pub fn create_table_from_entity<E>(entity: E) -> TableCreateStatement
+    pub fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
     where
         E: EntityTrait,
     {
-        create_table_from_entity(entity)
+        create_table_from_entity(entity, db_backend)
     }
 }
 
-pub(crate) fn create_table_from_entity<E>(entity: E) -> TableCreateStatement
+pub(crate) fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
 where
     E: EntityTrait,
 {
@@ -21,7 +21,9 @@ where
 
     for column in E::Column::iter() {
         let orm_column_def = column.def();
-        let types = orm_column_def.col_type.into();
+        let types = match db_backend {
+            _ => orm_column_def.col_type.into(),
+        };
         let mut column_def = ColumnDef::new_with_type(column, types);
         if !orm_column_def.null {
             column_def.not_null();
@@ -121,13 +123,14 @@ where
 
 #[cfg(test)]
 mod tests {
-    use crate::{sea_query::*, tests_cfg::*, Schema};
+    use crate::{sea_query::*, tests_cfg::*, DbBackend, Schema};
     use pretty_assertions::assert_eq;
 
     #[test]
     fn test_create_table_from_entity() {
         assert_eq!(
-            Schema::create_table_from_entity(CakeFillingPrice).to_string(MysqlQueryBuilder),
+            Schema::create_table_from_entity(CakeFillingPrice, DbBackend::MySql)
+                .to_string(MysqlQueryBuilder),
             Table::create()
                 .table(CakeFillingPrice)
                 .col(
diff --git a/tests/common/setup/mod.rs b/tests/common/setup/mod.rs
index 615de234c8..7266d17595 100644
--- a/tests/common/setup/mod.rs
+++ b/tests/common/setup/mod.rs
@@ -95,7 +95,10 @@ where
 
     let stmt = builder.build(create);
     assert_eq!(
-        builder.build(&Schema::create_table_from_entity(entity)),
+        builder.build(&Schema::create_table_from_entity(
+            entity,
+            db.get_database_backend()
+        )),
         stmt
     );
     db.execute(stmt).await

From f20c64988df6c4657cd625bfd33c69daee92cc7d Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Mon, 25 Oct 2021 16:52:02 +0800
Subject: [PATCH 06/16] Tests all DB

---
 src/entity/column.rs                 |  7 ++++---
 src/schema/entity.rs                 | 14 ++++++++++---
 tests/common/features/active_enum.rs |  5 ++++-
 tests/common/features/schema.rs      | 30 +++++++++++++++++-----------
 4 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/src/entity/column.rs b/src/entity/column.rs
index 32fe030c6d..4b9af89fef 100644
--- a/src/entity/column.rs
+++ b/src/entity/column.rs
@@ -34,7 +34,7 @@ pub enum ColumnType {
     JsonBinary,
     Custom(String),
     Uuid,
-    Enum(String),
+    Enum(String, Vec<String>),
 }
 
 macro_rules! bind_oper {
@@ -245,7 +245,8 @@ impl ColumnType {
 
     pub(crate) fn get_enum_name(&self) -> Option<&String> {
         match self {
-            ColumnType::Enum(s) => Some(s),
+            // FIXME: How to get rid of this feature gate?
+            ColumnType::Enum(s, _) if cfg!(feature = "sqlx-postgres") => Some(s),
             _ => None,
         }
     }
@@ -303,7 +304,7 @@ impl From<ColumnType> 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(s) => {
+            ColumnType::Enum(s, _) => {
                 sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s)))
             }
         }
diff --git a/src/schema/entity.rs b/src/schema/entity.rs
index 2d0aa13a1a..3f99f89283 100644
--- a/src/schema/entity.rs
+++ b/src/schema/entity.rs
@@ -1,6 +1,6 @@
 use crate::{
-    unpack_table_ref, ColumnTrait, DbBackend, EntityTrait, Identity, Iterable, PrimaryKeyToColumn,
-    PrimaryKeyTrait, RelationTrait, Schema,
+    unpack_table_ref, ColumnTrait, ColumnType, DbBackend, EntityTrait, Identity, Iterable,
+    PrimaryKeyToColumn, PrimaryKeyTrait, RelationTrait, Schema,
 };
 use sea_query::{ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement};
 
@@ -21,7 +21,15 @@ where
 
     for column in E::Column::iter() {
         let orm_column_def = column.def();
-        let types = match db_backend {
+        let types = match orm_column_def.col_type {
+            ColumnType::Enum(s, variants) => match db_backend {
+                DbBackend::MySql => {
+                    ColumnType::Custom(format!("ENUM('{}')", variants.join("', '")))
+                }
+                DbBackend::Postgres => ColumnType::Custom(s),
+                DbBackend::Sqlite => ColumnType::Text,
+            }
+            .into(),
             _ => orm_column_def.col_type.into(),
         };
         let mut column_def = ColumnDef::new_with_type(column, types);
diff --git a/tests/common/features/active_enum.rs b/tests/common/features/active_enum.rs
index 229d44466f..78f2179008 100644
--- a/tests/common/features/active_enum.rs
+++ b/tests/common/features/active_enum.rs
@@ -34,7 +34,10 @@ pub enum Color {
 }
 
 #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
-#[sea_orm(rs_type = "String", db_type = r#"Enum("tea".to_owned())"#)]
+#[sea_orm(
+    rs_type = "String",
+    db_type = r#"Enum("tea".to_owned(), vec!["EverydayTea".to_owned(), "BreakfastTea".to_owned()])"#
+)]
 pub enum Tea {
     #[sea_orm(string_value = "EverydayTea")]
     EverydayTea,
diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs
index ffb47f2692..0eeb5c0455 100644
--- a/tests/common/features/schema.rs
+++ b/tests/common/features/schema.rs
@@ -2,8 +2,13 @@ pub use super::super::bakery_chain::*;
 
 use super::*;
 use crate::common::setup::create_table;
-use sea_orm::{error::*, sea_query, DatabaseConnection, DbConn, ExecResult};
-use sea_query::{Alias, ColumnDef, ForeignKeyCreateStatement};
+use sea_orm::{
+    error::*, sea_query, ConnectionTrait, DatabaseConnection, DbBackend, DbConn, ExecResult,
+    Statement,
+};
+use sea_query::{
+    extension::postgres::Type, Alias, ColumnDef, ForeignKeyCreateStatement, PostgresQueryBuilder,
+};
 
 pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> {
     create_log_table(db).await?;
@@ -103,8 +108,16 @@ pub async fn create_self_join_table(db: &DbConn) -> Result<ExecResult, DbErr> {
 }
 
 pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr> {
+    let db_backend = db.get_database_backend();
     let tea_enum = Alias::new("tea");
 
+    let mut tea_col = ColumnDef::new(active_enum::Column::Tea);
+    match db_backend {
+        DbBackend::MySql => tea_col.custom(Alias::new("ENUM('EverydayTea', 'BreakfastTea')")),
+        DbBackend::Postgres => tea_col.custom(tea_enum.clone()),
+        DbBackend::Sqlite => tea_col.text(),
+    };
+
     let stmt = sea_query::Table::create()
         .table(active_enum::Entity)
         .col(
@@ -116,15 +129,11 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
         )
         .col(ColumnDef::new(active_enum::Column::Category).string_len(1))
         .col(ColumnDef::new(active_enum::Column::Color).integer())
-        .col(ColumnDef::new(active_enum::Column::Tea).custom(tea_enum.clone()))
+        .col(&mut tea_col)
         .to_owned();
 
-    match db {
-        #[cfg(feature = "sqlx-postgres")]
-        DatabaseConnection::SqlxPostgresPoolConnection(_) => {
-            use sea_orm::{ConnectionTrait, Statement};
-            use sea_query::{extension::postgres::Type, PostgresQueryBuilder};
-
+    match db_backend {
+        DbBackend::Postgres => {
             let drop_type_stmt = Type::drop()
                 .name(tea_enum.clone())
                 .cascade()
@@ -138,19 +147,16 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
                 .as_enum(tea_enum)
                 .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")])
                 .to_owned();
-
             // FIXME: This is not working
             {
                 let (sql, values) = create_type_stmt.build(PostgresQueryBuilder);
                 let _stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
             }
-
             // But this is working...
             let stmt = Statement::from_string(
                 db.get_database_backend(),
                 create_type_stmt.to_string(PostgresQueryBuilder),
             );
-
             db.execute(stmt).await?;
         }
         _ => {}

From 6059cdd9adf7af4768b1dd727b6730dfcc930c46 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Mon, 25 Oct 2021 16:56:36 +0800
Subject: [PATCH 07/16] Remove unused EnumIter

---
 src/entity/active_enum.rs            | 18 +++++++++---------
 tests/common/features/active_enum.rs |  6 +++---
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/entity/active_enum.rs b/src/entity/active_enum.rs
index 230ee8f2ab..5eb77b9f2b 100644
--- a/src/entity/active_enum.rs
+++ b/src/entity/active_enum.rs
@@ -1,4 +1,4 @@
-use crate::{ColumnDef, DbErr, Iterable, TryGetable};
+use crate::{ColumnDef, DbErr, TryGetable};
 use sea_query::{Nullable, Value, ValueType};
 
 /// A Rust representation of enum defined in database.
@@ -17,7 +17,7 @@ use sea_query::{Nullable, Value, ValueType};
 /// use sea_orm::entity::prelude::*;
 ///
 /// // Using the derive macro
-/// #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
+/// #[derive(Debug, PartialEq, DeriveActiveEnum)]
 /// #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
 /// pub enum DeriveCategory {
 ///     #[sea_orm(string_value = "B")]
@@ -27,7 +27,7 @@ use sea_query::{Nullable, Value, ValueType};
 /// }
 ///
 /// // Implementing it manually
-/// #[derive(Debug, PartialEq, EnumIter)]
+/// #[derive(Debug, PartialEq)]
 /// pub enum Category {
 ///     Big,
 ///     Small,
@@ -71,7 +71,7 @@ use sea_query::{Nullable, Value, ValueType};
 /// use sea_orm::entity::prelude::*;
 ///
 /// // Define the `Category` active enum
-/// #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
+/// #[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
 /// #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
 /// pub enum Category {
 ///     #[sea_orm(string_value = "B")]
@@ -95,7 +95,7 @@ use sea_query::{Nullable, Value, ValueType};
 ///
 /// impl ActiveModelBehavior for ActiveModel {}
 /// ```
-pub trait ActiveEnum: Sized + Iterable {
+pub trait ActiveEnum: Sized {
     /// Define the Rust type that each enum variant represents.
     type Value: Into<Value> + ValueType + Nullable + TryGetable;
 
@@ -117,7 +117,7 @@ mod tests {
 
     #[test]
     fn active_enum_string() {
-        #[derive(Debug, PartialEq, EnumIter)]
+        #[derive(Debug, PartialEq)]
         pub enum Category {
             Big,
             Small,
@@ -150,7 +150,7 @@ mod tests {
             }
         }
 
-        #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
+        #[derive(Debug, PartialEq, DeriveActiveEnum)]
         #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
         pub enum DeriveCategory {
             #[sea_orm(string_value = "B")]
@@ -201,7 +201,7 @@ mod tests {
     fn active_enum_derive_signed_integers() {
         macro_rules! test_int {
             ($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
-                #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
+                #[derive(Debug, PartialEq, DeriveActiveEnum)]
                 #[sea_orm(rs_type = $rs_type, db_type = $db_type)]
                 pub enum $ident {
                     #[sea_orm(num_value = 1)]
@@ -241,7 +241,7 @@ mod tests {
     fn active_enum_derive_unsigned_integers() {
         macro_rules! test_uint {
             ($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
-                #[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
+                #[derive(Debug, PartialEq, DeriveActiveEnum)]
                 #[sea_orm(rs_type = $rs_type, db_type = $db_type)]
                 pub enum $ident {
                     #[sea_orm(num_value = 1)]
diff --git a/tests/common/features/active_enum.rs b/tests/common/features/active_enum.rs
index 78f2179008..f152f37c39 100644
--- a/tests/common/features/active_enum.rs
+++ b/tests/common/features/active_enum.rs
@@ -15,7 +15,7 @@ pub enum Relation {}
 
 impl ActiveModelBehavior for ActiveModel {}
 
-#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
 #[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
 pub enum Category {
     #[sea_orm(string_value = "B")]
@@ -24,7 +24,7 @@ pub enum Category {
     Small,
 }
 
-#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
 #[sea_orm(rs_type = "i32", db_type = r#"Integer"#)]
 pub enum Color {
     #[sea_orm(num_value = 0)]
@@ -33,7 +33,7 @@ pub enum Color {
     White,
 }
 
-#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)]
+#[derive(Debug, Clone, PartialEq, DeriveActiveEnum)]
 #[sea_orm(
     rs_type = "String",
     db_type = r#"Enum("tea".to_owned(), vec!["EverydayTea".to_owned(), "BreakfastTea".to_owned()])"#

From 4b1cac7f354242dac9af2b9fa6698e9e30ef3f07 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Mon, 25 Oct 2021 17:05:27 +0800
Subject: [PATCH 08/16] Refactoring

---
 tests/common/features/schema.rs | 51 ++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 27 deletions(-)

diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs
index 0eeb5c0455..f630ccb790 100644
--- a/tests/common/features/schema.rs
+++ b/tests/common/features/schema.rs
@@ -132,34 +132,31 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
         .col(&mut tea_col)
         .to_owned();
 
-    match db_backend {
-        DbBackend::Postgres => {
-            let drop_type_stmt = Type::drop()
-                .name(tea_enum.clone())
-                .cascade()
-                .if_exists()
-                .to_owned();
-            let (sql, values) = drop_type_stmt.build(PostgresQueryBuilder);
-            let stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
-            db.execute(stmt).await?;
-
-            let create_type_stmt = Type::create()
-                .as_enum(tea_enum)
-                .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")])
-                .to_owned();
-            // FIXME: This is not working
-            {
-                let (sql, values) = create_type_stmt.build(PostgresQueryBuilder);
-                let _stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
-            }
-            // But this is working...
-            let stmt = Statement::from_string(
-                db.get_database_backend(),
-                create_type_stmt.to_string(PostgresQueryBuilder),
-            );
-            db.execute(stmt).await?;
+    if db_backend = DbBackend::Postgres {
+        let drop_type_stmt = Type::drop()
+            .name(tea_enum.clone())
+            .cascade()
+            .if_exists()
+            .to_owned();
+        let (sql, values) = drop_type_stmt.build(PostgresQueryBuilder);
+        let stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
+        db.execute(stmt).await?;
+
+        let create_type_stmt = Type::create()
+            .as_enum(tea_enum)
+            .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")])
+            .to_owned();
+        // FIXME: This is not working
+        {
+            let (sql, values) = create_type_stmt.build(PostgresQueryBuilder);
+            let _stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
         }
-        _ => {}
+        // But this is working...
+        let stmt = Statement::from_string(
+            db.get_database_backend(),
+            create_type_stmt.to_string(PostgresQueryBuilder),
+        );
+        db.execute(stmt).await?;
     }
 
     create_table(db, &stmt, ActiveEnum).await

From cf52839c3ac4564a10790b060d0e97b37f3daf1f Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Mon, 25 Oct 2021 17:12:17 +0800
Subject: [PATCH 09/16] Typo

---
 tests/common/features/schema.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs
index f630ccb790..bbc9faf8be 100644
--- a/tests/common/features/schema.rs
+++ b/tests/common/features/schema.rs
@@ -132,7 +132,7 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
         .col(&mut tea_col)
         .to_owned();
 
-    if db_backend = DbBackend::Postgres {
+    if db_backend == DbBackend::Postgres {
         let drop_type_stmt = Type::drop()
             .name(tea_enum.clone())
             .cascade()

From 2ee376ddd117b2e14f16dd6e3952645c5fc7d007 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Tue, 26 Oct 2021 16:22:24 +0800
Subject: [PATCH 10/16] Try `EnumValue`

---
 src/entity/column.rs | 3 +--
 src/query/insert.rs  | 4 ++--
 src/query/select.rs  | 4 ++--
 src/query/update.rs  | 4 ++--
 4 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/entity/column.rs b/src/entity/column.rs
index 4b9af89fef..8cd65d9cb2 100644
--- a/src/entity/column.rs
+++ b/src/entity/column.rs
@@ -245,8 +245,7 @@ impl ColumnType {
 
     pub(crate) fn get_enum_name(&self) -> Option<&String> {
         match self {
-            // FIXME: How to get rid of this feature gate?
-            ColumnType::Enum(s, _) if cfg!(feature = "sqlx-postgres") => Some(s),
+            ColumnType::Enum(s, _) => Some(s),
             _ => None,
         }
     }
diff --git a/src/query/insert.rs b/src/query/insert.rs
index 3a7c91d67e..a1b34f501b 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -3,7 +3,7 @@ use crate::{
     PrimaryKeyTrait, QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{Alias, Expr, Func, InsertStatement, ValueTuple};
+use sea_query::{Expr, InsertStatement, SimpleExpr, ValueTuple};
 
 #[derive(Debug)]
 pub struct Insert<A>
@@ -136,7 +136,7 @@ where
                 columns.push(col);
                 let val = av.into_value().unwrap();
                 let expr = if let Some(enum_name) = enum_name {
-                    Func::cast_as(val, Alias::new(enum_name))
+                    SimpleExpr::EnumValue(enum_name.to_owned(), Box::new(Expr::val(val).into()))
                 } else {
                     Expr::val(val).into()
                 };
diff --git a/src/query/select.rs b/src/query/select.rs
index 0f2db65bf8..1bdfce1a07 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -2,7 +2,7 @@ use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySe
 use core::fmt::Debug;
 use core::marker::PhantomData;
 pub use sea_query::JoinType;
-use sea_query::{Alias, DynIden, Expr, Func, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
+use sea_query::{DynIden, Expr, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
 
 #[derive(Clone, Debug)]
 pub struct Select<E>
@@ -121,7 +121,7 @@ where
                 let enum_name = col_def.get_column_type().get_enum_name();
                 let col_expr = Expr::tbl(table.clone(), col);
                 if enum_name.is_some() {
-                    Func::cast_expr_as(col_expr, Alias::new("text"))
+                    SimpleExpr::EnumValue("text".to_owned(), Box::new(col_expr.into()))
                 } else {
                     col_expr.into()
                 }
diff --git a/src/query/update.rs b/src/query/update.rs
index a881ad1154..a81b5607e0 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -3,7 +3,7 @@ use crate::{
     QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{Alias, Expr, Func, IntoIden, SimpleExpr, UpdateStatement};
+use sea_query::{Expr, IntoIden, SimpleExpr, UpdateStatement};
 
 #[derive(Clone, Debug)]
 pub struct Update;
@@ -110,7 +110,7 @@ where
             if av.is_set() {
                 let val = av.into_value().unwrap();
                 let expr = if let Some(enum_name) = enum_name {
-                    Func::cast_as(val, Alias::new(enum_name))
+                    SimpleExpr::EnumValue(enum_name.to_owned(), Box::new(Expr::val(val).into()))
                 } else {
                     Expr::val(val).into()
                 };

From db22e70c6339f65e0cb40d9b2a0aa034c6183d60 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Tue, 26 Oct 2021 17:51:36 +0800
Subject: [PATCH 11/16] Refactoring

---
 src/query/insert.rs | 8 ++++----
 src/query/select.rs | 2 +-
 src/query/update.rs | 6 +++---
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/query/insert.rs b/src/query/insert.rs
index a1b34f501b..63f22c35b3 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -3,7 +3,7 @@ use crate::{
     PrimaryKeyTrait, QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{Expr, InsertStatement, SimpleExpr, ValueTuple};
+use sea_query::{Expr, InsertStatement, ValueTuple};
 
 #[derive(Debug)]
 pub struct Insert<A>
@@ -134,11 +134,11 @@ where
             }
             if av_has_val {
                 columns.push(col);
-                let val = av.into_value().unwrap();
+                let val = Expr::val(av.into_value().unwrap());
                 let expr = if let Some(enum_name) = enum_name {
-                    SimpleExpr::EnumValue(enum_name.to_owned(), Box::new(Expr::val(val).into()))
+                    Expr::enum_value(enum_name, val)
                 } else {
-                    Expr::val(val).into()
+                    val.into()
                 };
                 values.push(expr);
             }
diff --git a/src/query/select.rs b/src/query/select.rs
index 1bdfce1a07..5a270f6d8e 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -121,7 +121,7 @@ where
                 let enum_name = col_def.get_column_type().get_enum_name();
                 let col_expr = Expr::tbl(table.clone(), col);
                 if enum_name.is_some() {
-                    SimpleExpr::EnumValue("text".to_owned(), Box::new(col_expr.into()))
+                    Expr::enum_value("text", col_expr)
                 } else {
                     col_expr.into()
                 }
diff --git a/src/query/update.rs b/src/query/update.rs
index a81b5607e0..18e4594b9c 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -108,11 +108,11 @@ where
             let enum_name = col_def.get_column_type().get_enum_name();
             let av = self.model.get(col);
             if av.is_set() {
-                let val = av.into_value().unwrap();
+                let val = Expr::val(av.into_value().unwrap());
                 let expr = if let Some(enum_name) = enum_name {
-                    SimpleExpr::EnumValue(enum_name.to_owned(), Box::new(Expr::val(val).into()))
+                    Expr::enum_value(enum_name, val)
                 } else {
-                    Expr::val(val).into()
+                    val.into()
                 };
                 self.query.value_expr(col, expr);
             }

From ded28be2c01a744a80bcb92cae4e3922b29f7baa Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Tue, 26 Oct 2021 18:58:06 +0800
Subject: [PATCH 12/16] Refactoring

---
 src/entity/column.rs | 5 +----
 src/query/insert.rs  | 4 ++--
 src/query/select.rs  | 5 +++--
 src/query/update.rs  | 4 ++--
 4 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/src/entity/column.rs b/src/entity/column.rs
index 8cd65d9cb2..9a1f5c9de6 100644
--- a/src/entity/column.rs
+++ b/src/entity/column.rs
@@ -299,13 +299,10 @@ impl From<ColumnType> for sea_query::ColumnType {
             ColumnType::Money(s) => sea_query::ColumnType::Money(s),
             ColumnType::Json => sea_query::ColumnType::Json,
             ColumnType::JsonBinary => sea_query::ColumnType::JsonBinary,
-            ColumnType::Custom(s) => {
+            ColumnType::Custom(s) | ColumnType::Enum(s, _) => {
                 sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s)))
             }
             ColumnType::Uuid => sea_query::ColumnType::Uuid,
-            ColumnType::Enum(s, _) => {
-                sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s)))
-            }
         }
     }
 }
diff --git a/src/query/insert.rs b/src/query/insert.rs
index 63f22c35b3..8719e01188 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -3,7 +3,7 @@ use crate::{
     PrimaryKeyTrait, QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{Expr, InsertStatement, ValueTuple};
+use sea_query::{Alias, Expr, InsertStatement, ValueTuple};
 
 #[derive(Debug)]
 pub struct Insert<A>
@@ -136,7 +136,7 @@ where
                 columns.push(col);
                 let val = Expr::val(av.into_value().unwrap());
                 let expr = if let Some(enum_name) = enum_name {
-                    Expr::enum_value(enum_name, val)
+                    val.as_enum(Alias::new(enum_name))
                 } else {
                     val.into()
                 };
diff --git a/src/query/select.rs b/src/query/select.rs
index 5a270f6d8e..5c6d1f3b22 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -2,7 +2,7 @@ use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySe
 use core::fmt::Debug;
 use core::marker::PhantomData;
 pub use sea_query::JoinType;
-use sea_query::{DynIden, Expr, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
+use sea_query::{Alias, DynIden, Expr, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
 
 #[derive(Clone, Debug)]
 pub struct Select<E>
@@ -115,13 +115,14 @@ where
 
     fn column_list(&self) -> Vec<SimpleExpr> {
         let table = SeaRc::new(E::default()) as DynIden;
+        let text_type = SeaRc::new(Alias::new("text")) as DynIden;
         E::Column::iter()
             .map(|col| {
                 let col_def = col.def();
                 let enum_name = col_def.get_column_type().get_enum_name();
                 let col_expr = Expr::tbl(table.clone(), col);
                 if enum_name.is_some() {
-                    Expr::enum_value("text", col_expr)
+                    col_expr.as_enum(text_type.clone())
                 } else {
                     col_expr.into()
                 }
diff --git a/src/query/update.rs b/src/query/update.rs
index 18e4594b9c..6b6f48f831 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -3,7 +3,7 @@ use crate::{
     QueryTrait,
 };
 use core::marker::PhantomData;
-use sea_query::{Expr, IntoIden, SimpleExpr, UpdateStatement};
+use sea_query::{Alias, Expr, IntoIden, SimpleExpr, UpdateStatement};
 
 #[derive(Clone, Debug)]
 pub struct Update;
@@ -110,7 +110,7 @@ where
             if av.is_set() {
                 let val = Expr::val(av.into_value().unwrap());
                 let expr = if let Some(enum_name) = enum_name {
-                    Expr::enum_value(enum_name, val)
+                    val.as_enum(Alias::new(enum_name))
                 } else {
                     val.into()
                 };

From fac528a3699b0b6c9e0ced88553ad5720acc4db4 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Wed, 27 Oct 2021 10:58:38 +0800
Subject: [PATCH 13/16] Refactoring

---
 src/query/insert.rs |  8 +++-----
 src/query/select.rs | 10 ++++------
 src/query/update.rs |  8 +++-----
 3 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/src/query/insert.rs b/src/query/insert.rs
index 8719e01188..f8b151d7b3 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -125,7 +125,6 @@ where
             let av = am.take(col);
             let av_has_val = av.is_set() || av.is_unchanged();
             let col_def = col.def();
-            let enum_name = col_def.get_column_type().get_enum_name();
 
             if columns_empty {
                 self.columns.push(av_has_val);
@@ -135,10 +134,9 @@ where
             if av_has_val {
                 columns.push(col);
                 let val = Expr::val(av.into_value().unwrap());
-                let expr = if let Some(enum_name) = enum_name {
-                    val.as_enum(Alias::new(enum_name))
-                } else {
-                    val.into()
+                let expr = match col_def.get_column_type().get_enum_name() {
+                    Some(enum_name) => val.as_enum(Alias::new(enum_name)),
+                    None => val.into(),
                 };
                 values.push(expr);
             }
diff --git a/src/query/select.rs b/src/query/select.rs
index 5c6d1f3b22..037527c760 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -119,12 +119,10 @@ where
         E::Column::iter()
             .map(|col| {
                 let col_def = col.def();
-                let enum_name = col_def.get_column_type().get_enum_name();
-                let col_expr = Expr::tbl(table.clone(), col);
-                if enum_name.is_some() {
-                    col_expr.as_enum(text_type.clone())
-                } else {
-                    col_expr.into()
+                let expr = Expr::tbl(table.clone(), col);
+                match col_def.get_column_type().get_enum_name() {
+                    Some(_) => expr.as_enum(text_type.clone()),
+                    None => expr.into(),
                 }
             })
             .collect()
diff --git a/src/query/update.rs b/src/query/update.rs
index 6b6f48f831..7c2e9c2e65 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -105,14 +105,12 @@ where
                 continue;
             }
             let col_def = col.def();
-            let enum_name = col_def.get_column_type().get_enum_name();
             let av = self.model.get(col);
             if av.is_set() {
                 let val = Expr::val(av.into_value().unwrap());
-                let expr = if let Some(enum_name) = enum_name {
-                    val.as_enum(Alias::new(enum_name))
-                } else {
-                    val.into()
+                let expr = match col_def.get_column_type().get_enum_name() {
+                    Some(enum_name) => val.as_enum(Alias::new(enum_name)),
+                    None => val.into(),
                 };
                 self.query.value_expr(col, expr);
             }

From e04495b94d2e1849132ce4bd679ce32f4d7a4756 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Wed, 27 Oct 2021 11:28:33 +0800
Subject: [PATCH 14/16] Refactoring

---
 src/query/insert.rs | 4 +---
 src/query/select.rs | 3 +--
 src/query/update.rs | 3 +--
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/src/query/insert.rs b/src/query/insert.rs
index f8b151d7b3..f7f77d7d0c 100644
--- a/src/query/insert.rs
+++ b/src/query/insert.rs
@@ -124,8 +124,6 @@ where
         for (idx, col) in <A::Entity as EntityTrait>::Column::iter().enumerate() {
             let av = am.take(col);
             let av_has_val = av.is_set() || av.is_unchanged();
-            let col_def = col.def();
-
             if columns_empty {
                 self.columns.push(av_has_val);
             } else if self.columns[idx] != av_has_val {
@@ -134,7 +132,7 @@ where
             if av_has_val {
                 columns.push(col);
                 let val = Expr::val(av.into_value().unwrap());
-                let expr = match col_def.get_column_type().get_enum_name() {
+                let expr = match col.def().get_column_type().get_enum_name() {
                     Some(enum_name) => val.as_enum(Alias::new(enum_name)),
                     None => val.into(),
                 };
diff --git a/src/query/select.rs b/src/query/select.rs
index 037527c760..5e433e8a44 100644
--- a/src/query/select.rs
+++ b/src/query/select.rs
@@ -118,9 +118,8 @@ where
         let text_type = SeaRc::new(Alias::new("text")) as DynIden;
         E::Column::iter()
             .map(|col| {
-                let col_def = col.def();
                 let expr = Expr::tbl(table.clone(), col);
-                match col_def.get_column_type().get_enum_name() {
+                match col.def().get_column_type().get_enum_name() {
                     Some(_) => expr.as_enum(text_type.clone()),
                     None => expr.into(),
                 }
diff --git a/src/query/update.rs b/src/query/update.rs
index 7c2e9c2e65..89348229a8 100644
--- a/src/query/update.rs
+++ b/src/query/update.rs
@@ -104,11 +104,10 @@ where
             if <A::Entity as EntityTrait>::PrimaryKey::from_column(col).is_some() {
                 continue;
             }
-            let col_def = col.def();
             let av = self.model.get(col);
             if av.is_set() {
                 let val = Expr::val(av.into_value().unwrap());
-                let expr = match col_def.get_column_type().get_enum_name() {
+                let expr = match col.def().get_column_type().get_enum_name() {
                     Some(enum_name) => val.as_enum(Alias::new(enum_name)),
                     None => val.into(),
                 };

From 55de1968bbb049c506c60b2df9f84a252ce0e4ad Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Wed, 27 Oct 2021 12:37:35 +0800
Subject: [PATCH 15/16] Add `create_enum_from_entity`

---
 src/database/statement.rs       | 24 ++++++++++++++
 src/schema/entity.rs            | 39 ++++++++++++++++++++++-
 tests/common/features/schema.rs | 51 +++++++++---------------------
 tests/common/setup/mod.rs       | 55 +++++++++++++++++++++++++++++++--
 4 files changed, 129 insertions(+), 40 deletions(-)

diff --git a/src/database/statement.rs b/src/database/statement.rs
index 12b074873d..86d7c630d3 100644
--- a/src/database/statement.rs
+++ b/src/database/statement.rs
@@ -73,6 +73,15 @@ macro_rules! build_any_stmt {
     };
 }
 
+macro_rules! build_postgres_stmt {
+    ($stmt: expr, $db_backend: expr) => {
+        match $db_backend {
+            DbBackend::Postgres => $stmt.to_string(PostgresQueryBuilder),
+            DbBackend::MySql | DbBackend::Sqlite => unimplemented!(),
+        }
+    };
+}
+
 macro_rules! build_query_stmt {
     ($stmt: ty) => {
         impl StatementBuilder for $stmt {
@@ -105,3 +114,18 @@ build_schema_stmt!(sea_query::TableDropStatement);
 build_schema_stmt!(sea_query::TableAlterStatement);
 build_schema_stmt!(sea_query::TableRenameStatement);
 build_schema_stmt!(sea_query::TableTruncateStatement);
+
+macro_rules! build_type_stmt {
+    ($stmt: ty) => {
+        impl StatementBuilder for $stmt {
+            fn build(&self, db_backend: &DbBackend) -> Statement {
+                let stmt = build_postgres_stmt!(self, db_backend);
+                Statement::from_string(*db_backend, stmt)
+            }
+        }
+    };
+}
+
+build_type_stmt!(sea_query::extension::postgres::TypeAlterStatement);
+build_type_stmt!(sea_query::extension::postgres::TypeCreateStatement);
+build_type_stmt!(sea_query::extension::postgres::TypeDropStatement);
diff --git a/src/schema/entity.rs b/src/schema/entity.rs
index 3f99f89283..238bde36e2 100644
--- a/src/schema/entity.rs
+++ b/src/schema/entity.rs
@@ -2,9 +2,19 @@ use crate::{
     unpack_table_ref, ColumnTrait, ColumnType, DbBackend, EntityTrait, Identity, Iterable,
     PrimaryKeyToColumn, PrimaryKeyTrait, RelationTrait, Schema,
 };
-use sea_query::{ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement};
+use sea_query::{
+    extension::postgres::{Type, TypeCreateStatement},
+    Alias, ColumnDef, ForeignKeyCreateStatement, Iden, Index, TableCreateStatement,
+};
 
 impl Schema {
+    pub fn create_enum_from_entity<E>(entity: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
+    where
+        E: EntityTrait,
+    {
+        create_enum_from_entity(entity, db_backend)
+    }
+
     pub fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
     where
         E: EntityTrait,
@@ -13,6 +23,33 @@ impl Schema {
     }
 }
 
+pub(crate) fn create_enum_from_entity<E>(_: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
+where
+    E: EntityTrait,
+{
+    if matches!(db_backend, DbBackend::MySql | DbBackend::Sqlite) {
+        return Vec::new();
+    }
+    let mut vec = Vec::new();
+    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(_, _)) {
+            continue;
+        }
+        let (name, values) = match col_type {
+            ColumnType::Enum(s, v) => (s.as_str(), v),
+            _ => unreachable!(),
+        };
+        let stmt = Type::create()
+            .as_enum(Alias::new(name))
+            .values(values.into_iter().map(|val| Alias::new(val.as_str())))
+            .to_owned();
+        vec.push(stmt);
+    }
+    vec
+}
+
 pub(crate) fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
 where
     E: EntityTrait,
diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs
index bbc9faf8be..7e9f3de7b4 100644
--- a/tests/common/features/schema.rs
+++ b/tests/common/features/schema.rs
@@ -1,14 +1,11 @@
 pub use super::super::bakery_chain::*;
 
 use super::*;
-use crate::common::setup::create_table;
+use crate::{common::setup::create_table, create_enum};
 use sea_orm::{
     error::*, sea_query, ConnectionTrait, DatabaseConnection, DbBackend, DbConn, ExecResult,
-    Statement,
-};
-use sea_query::{
-    extension::postgres::Type, Alias, ColumnDef, ForeignKeyCreateStatement, PostgresQueryBuilder,
 };
+use sea_query::{extension::postgres::Type, Alias, ColumnDef, ForeignKeyCreateStatement};
 
 pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> {
     create_log_table(db).await?;
@@ -111,14 +108,23 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
     let db_backend = db.get_database_backend();
     let tea_enum = Alias::new("tea");
 
+    let create_enum_stmts = match db_backend {
+        DbBackend::MySql | DbBackend::Sqlite => Vec::new(),
+        DbBackend::Postgres => vec![Type::create()
+            .as_enum(tea_enum.clone())
+            .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")])
+            .to_owned()],
+    };
+
+    create_enum(db, &create_enum_stmts, ActiveEnum).await?;
+
     let mut tea_col = ColumnDef::new(active_enum::Column::Tea);
     match db_backend {
         DbBackend::MySql => tea_col.custom(Alias::new("ENUM('EverydayTea', 'BreakfastTea')")),
-        DbBackend::Postgres => tea_col.custom(tea_enum.clone()),
         DbBackend::Sqlite => tea_col.text(),
+        DbBackend::Postgres => tea_col.custom(tea_enum),
     };
-
-    let stmt = sea_query::Table::create()
+    let create_table_stmt = sea_query::Table::create()
         .table(active_enum::Entity)
         .col(
             ColumnDef::new(active_enum::Column::Id)
@@ -132,32 +138,5 @@ pub async fn create_active_enum_table(db: &DbConn) -> Result<ExecResult, DbErr>
         .col(&mut tea_col)
         .to_owned();
 
-    if db_backend == DbBackend::Postgres {
-        let drop_type_stmt = Type::drop()
-            .name(tea_enum.clone())
-            .cascade()
-            .if_exists()
-            .to_owned();
-        let (sql, values) = drop_type_stmt.build(PostgresQueryBuilder);
-        let stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
-        db.execute(stmt).await?;
-
-        let create_type_stmt = Type::create()
-            .as_enum(tea_enum)
-            .values(vec![Alias::new("EverydayTea"), Alias::new("BreakfastTea")])
-            .to_owned();
-        // FIXME: This is not working
-        {
-            let (sql, values) = create_type_stmt.build(PostgresQueryBuilder);
-            let _stmt = Statement::from_sql_and_values(db.get_database_backend(), &sql, values);
-        }
-        // But this is working...
-        let stmt = Statement::from_string(
-            db.get_database_backend(),
-            create_type_stmt.to_string(PostgresQueryBuilder),
-        );
-        db.execute(stmt).await?;
-    }
-
-    create_table(db, &stmt, ActiveEnum).await
+    create_table(db, &create_table_stmt, ActiveEnum).await
 }
diff --git a/tests/common/setup/mod.rs b/tests/common/setup/mod.rs
index 7266d17595..263e19f2fe 100644
--- a/tests/common/setup/mod.rs
+++ b/tests/common/setup/mod.rs
@@ -1,9 +1,12 @@
 use pretty_assertions::assert_eq;
 use sea_orm::{
-    ConnectionTrait, Database, DatabaseBackend, DatabaseConnection, DbBackend, DbConn, DbErr,
-    EntityTrait, ExecResult, Schema, Statement,
+    ColumnTrait, ColumnType, ConnectionTrait, Database, DatabaseBackend, DatabaseConnection,
+    DbBackend, DbConn, DbErr, EntityTrait, ExecResult, Iterable, Schema, Statement,
+};
+use sea_query::{
+    extension::postgres::{Type, TypeCreateStatement},
+    Alias, Table, TableCreateStatement,
 };
-use sea_query::{Alias, Table, TableCreateStatement};
 
 pub async fn setup(base_url: &str, db_name: &str) -> DatabaseConnection {
     let db = if cfg!(feature = "sqlx-mysql") {
@@ -74,6 +77,52 @@ pub async fn tear_down(base_url: &str, db_name: &str) {
     };
 }
 
+pub async fn create_enum<E>(
+    db: &DbConn,
+    creates: &[TypeCreateStatement],
+    entity: E,
+) -> Result<(), DbErr>
+where
+    E: EntityTrait,
+{
+    let builder = db.get_database_backend();
+    if builder == DbBackend::Postgres {
+        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(_, _)) {
+                continue;
+            }
+            let name = match col_type {
+                ColumnType::Enum(s, _) => s.as_str(),
+                _ => unreachable!(),
+            };
+            let drop_type_stmt = Type::drop()
+                .name(Alias::new(name))
+                .if_exists()
+                .cascade()
+                .to_owned();
+            let stmt = builder.build(&drop_type_stmt);
+            db.execute(stmt).await?;
+        }
+    }
+
+    let expect_stmts: Vec<Statement> = creates.iter().map(|stmt| builder.build(stmt)).collect();
+    let create_from_entity_stmts: Vec<Statement> =
+        Schema::create_enum_from_entity(entity, db.get_database_backend())
+            .iter()
+            .map(|stmt| builder.build(stmt))
+            .collect();
+
+    assert_eq!(expect_stmts, create_from_entity_stmts);
+
+    for stmt in expect_stmts {
+        db.execute(stmt).await.map(|_| ())?;
+    }
+
+    Ok(())
+}
+
 pub async fn create_table<E>(
     db: &DbConn,
     create: &TableCreateStatement,

From f88c7259fe116c1bbcba69564e2090df4de17b70 Mon Sep 17 00:00:00 2001
From: Billy Chan <ccw.billy.123@gmail.com>
Date: Wed, 27 Oct 2021 12:50:02 +0800
Subject: [PATCH 16/16] Fixup

---
 tests/common/features/schema.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs
index 7e9f3de7b4..977b4b61c5 100644
--- a/tests/common/features/schema.rs
+++ b/tests/common/features/schema.rs
@@ -1,7 +1,7 @@
 pub use super::super::bakery_chain::*;
 
 use super::*;
-use crate::{common::setup::create_table, create_enum};
+use crate::common::setup::{create_table, create_enum};
 use sea_orm::{
     error::*, sea_query, ConnectionTrait, DatabaseConnection, DbBackend, DbConn, ExecResult,
 };
