Try Postgres enum

This commit is contained in:
Billy Chan 2021-10-21 15:40:22 +08:00
parent 734608471c
commit 80c72004d1
No known key found for this signature in database
GPG Key ID: A2D690CAC7DF3CC7
8 changed files with 96 additions and 16 deletions

View File

@ -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 }

View File

@ -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")]

View File

@ -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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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(())
}

View File

@ -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
}