From 11781082ba52806d4e33957069d2979bf16de1a4 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 28 Sep 2021 19:00:55 +0800 Subject: [PATCH 01/21] Throw error if none of the db rows are affected --- src/error.rs | 2 ++ src/executor/insert.rs | 4 ++-- src/executor/update.rs | 5 +++++ tests/crud/updates.rs | 13 +++++++++---- tests/uuid_tests.rs | 17 ++++++++++++++++- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index 09f80b0a..f8aff775 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,7 @@ pub enum DbErr { Conn(String), Exec(String), Query(String), + RecordNotFound(String), } impl std::error::Error for DbErr {} @@ -13,6 +14,7 @@ impl std::fmt::Display for DbErr { Self::Conn(s) => write!(f, "Connection Error: {}", s), Self::Exec(s) => write!(f, "Execution Error: {}", s), Self::Query(s) => write!(f, "Query Error: {}", s), + Self::RecordNotFound(s) => write!(f, "RecordNotFound Error: {}", s), } } } diff --git a/src/executor/insert.rs b/src/executor/insert.rs index d580f110..a44867f7 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -1,6 +1,6 @@ use crate::{ - error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, PrimaryKeyTrait, - Statement, TryFromU64, + error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, + PrimaryKeyTrait, Statement, TryFromU64, }; use sea_query::InsertStatement; use std::{future::Future, marker::PhantomData}; diff --git a/src/executor/update.rs b/src/executor/update.rs index 6c7a9873..c6668d6b 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -73,6 +73,11 @@ where // Only Statement impl Send async fn exec_update(statement: Statement, db: &DatabaseConnection) -> Result { let result = db.execute(statement).await?; + if result.rows_affected() <= 0 { + return Err(DbErr::RecordNotFound( + "None of the database rows are affected".to_owned(), + )); + } Ok(UpdateResult { rows_affected: result.rows_affected(), }) diff --git a/tests/crud/updates.rs b/tests/crud/updates.rs index c2048f9b..262031ef 100644 --- a/tests/crud/updates.rs +++ b/tests/crud/updates.rs @@ -1,5 +1,6 @@ pub use super::*; use rust_decimal_macros::dec; +use sea_orm::DbErr; use uuid::Uuid; pub async fn test_update_cake(db: &DbConn) { @@ -119,10 +120,14 @@ pub async fn test_update_deleted_customer(db: &DbConn) { ..Default::default() }; - let _customer_update_res: customer::ActiveModel = customer - .update(db) - .await - .expect("could not update customer"); + let customer_update_res = customer.update(db).await; + + assert_eq!( + customer_update_res, + Err(DbErr::RecordNotFound( + "None of the database rows are affected".to_owned() + )) + ); assert_eq!(Customer::find().count(db).await.unwrap(), init_n_customers); diff --git a/tests/uuid_tests.rs b/tests/uuid_tests.rs index e58daca4..052f57d7 100644 --- a/tests/uuid_tests.rs +++ b/tests/uuid_tests.rs @@ -1,7 +1,7 @@ pub mod common; pub use common::{bakery_chain::*, setup::*, TestContext}; -use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel}; +use sea_orm::{entity::prelude::*, DatabaseConnection, IntoActiveModel, Set}; #[sea_orm_macros::test] #[cfg(any( @@ -40,5 +40,20 @@ pub async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> { } ); + let update_res = Metadata::update(metadata::ActiveModel { + value: Set("0.22".to_owned()), + ..metadata.clone().into_active_model() + }) + .filter(metadata::Column::Uuid.eq(Uuid::default())) + .exec(db) + .await; + + assert_eq!( + update_res, + Err(DbErr::RecordNotFound( + "None of the database rows are affected".to_owned() + )) + ); + Ok(()) } From 966f7ff9a85fcb133fb863ca1af709da5ed2c7fb Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 28 Sep 2021 19:06:02 +0800 Subject: [PATCH 02/21] Fix clippy warning --- src/executor/update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/executor/update.rs b/src/executor/update.rs index c6668d6b..7cb60f3e 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -73,7 +73,7 @@ where // Only Statement impl Send async fn exec_update(statement: Statement, db: &DatabaseConnection) -> Result { let result = db.execute(statement).await?; - if result.rows_affected() <= 0 { + if result.rows_affected() == 0 { return Err(DbErr::RecordNotFound( "None of the database rows are affected".to_owned(), )); From f4218dec56b0745b75f88171ee7e0202115e9397 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 30 Sep 2021 12:47:01 +0800 Subject: [PATCH 03/21] Test mock connection --- src/executor/update.rs | 105 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/executor/update.rs b/src/executor/update.rs index 7cb60f3e..bcbafefc 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -82,3 +82,108 @@ async fn exec_update(statement: Statement, db: &DatabaseConnection) -> Result Result<(), DbErr> { + let db = MockDatabase::new(DbBackend::Postgres) + .append_query_results(vec![ + vec![cake::Model { + id: 1, + name: "Cheese Cake".to_owned(), + }], + vec![], + vec![], + ]) + .append_exec_results(vec![ + MockExecResult { + last_insert_id: 0, + rows_affected: 1, + }, + MockExecResult { + last_insert_id: 0, + rows_affected: 0, + }, + MockExecResult { + last_insert_id: 0, + rows_affected: 0, + }, + ]) + .into_connection(); + + let model = cake::Model { + id: 1, + name: "New York Cheese".to_owned(), + }; + + assert_eq!( + cake::ActiveModel { + name: Set("Cheese Cake".to_owned()), + ..model.into_active_model() + } + .update(&db) + .await?, + cake::Model { + id: 1, + name: "Cheese Cake".to_owned(), + } + .into_active_model() + ); + + let model = cake::Model { + id: 2, + name: "New York Cheese".to_owned(), + }; + + assert_eq!( + cake::ActiveModel { + name: Set("Cheese Cake".to_owned()), + ..model.clone().into_active_model() + } + .update(&db) + .await, + Err(DbErr::RecordNotFound( + "None of the database rows are affected".to_owned() + )) + ); + + assert_eq!( + cake::Entity::update(cake::ActiveModel { + name: Set("Cheese Cake".to_owned()), + ..model.into_active_model() + }) + .exec(&db) + .await, + Err(DbErr::RecordNotFound( + "None of the database rows are affected".to_owned() + )) + ); + + assert_eq!( + db.into_transaction_log(), + vec![ + Transaction::from_sql_and_values( + DbBackend::Postgres, + r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#, + vec!["Cheese Cake".into(), 1i32.into()] + ), + Transaction::from_sql_and_values( + DbBackend::Postgres, + r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#, + vec!["Cheese Cake".into(), 2i32.into()] + ), + Transaction::from_sql_and_values( + DbBackend::Postgres, + r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#, + vec!["Cheese Cake".into(), 2i32.into()] + ), + ] + ); + + Ok(()) + } +} From 602690e9a7c8c281cc33a185234fe1ee09492c47 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Thu, 30 Sep 2021 19:16:55 +0800 Subject: [PATCH 04/21] Remove unneeded --- src/executor/update.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/executor/update.rs b/src/executor/update.rs index bcbafefc..2bc5ed80 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -91,14 +91,6 @@ mod tests { #[smol_potat::test] async fn update_record_not_found_1() -> Result<(), DbErr> { let db = MockDatabase::new(DbBackend::Postgres) - .append_query_results(vec![ - vec![cake::Model { - id: 1, - name: "Cheese Cake".to_owned(), - }], - vec![], - vec![], - ]) .append_exec_results(vec![ MockExecResult { last_insert_id: 0, From 91fb97c12ae1e4ce4ebf87977f960198f475e365 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Mon, 4 Oct 2021 11:18:42 +0800 Subject: [PATCH 05/21] `Update::many()` will not raise `DbErr::RecordNotFound` error --- src/executor/update.rs | 65 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/executor/update.rs b/src/executor/update.rs index 2bc5ed80..b564165c 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -7,9 +7,10 @@ use std::future::Future; #[derive(Clone, Debug)] pub struct Updater { query: UpdateStatement, + check_record_exists: bool, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct UpdateResult { pub rows_affected: u64, } @@ -39,7 +40,15 @@ where impl Updater { pub fn new(query: UpdateStatement) -> Self { - Self { query } + Self { + query, + check_record_exists: false, + } + } + + pub fn check_record_exists(mut self) -> Self { + self.check_record_exists = true; + self } pub fn exec( @@ -47,7 +56,7 @@ impl Updater { db: &DatabaseConnection, ) -> impl Future> + '_ { let builder = db.get_database_backend(); - exec_update(builder.build(&self.query), db) + exec_update(builder.build(&self.query), db, self.check_record_exists) } } @@ -66,14 +75,18 @@ async fn exec_update_and_return_original( where A: ActiveModelTrait, { - Updater::new(query).exec(db).await?; + Updater::new(query).check_record_exists().exec(db).await?; Ok(model) } // Only Statement impl Send -async fn exec_update(statement: Statement, db: &DatabaseConnection) -> Result { +async fn exec_update( + statement: Statement, + db: &DatabaseConnection, + check_record_exists: bool, +) -> Result { let result = db.execute(statement).await?; - if result.rows_affected() == 0 { + if check_record_exists && result.rows_affected() == 0 { return Err(DbErr::RecordNotFound( "None of the database rows are affected".to_owned(), )); @@ -87,6 +100,7 @@ async fn exec_update(statement: Statement, db: &DatabaseConnection) -> Result Result<(), DbErr> { @@ -104,6 +118,14 @@ mod tests { last_insert_id: 0, rows_affected: 0, }, + MockExecResult { + last_insert_id: 0, + rows_affected: 0, + }, + MockExecResult { + last_insert_id: 0, + rows_affected: 0, + }, ]) .into_connection(); @@ -145,6 +167,18 @@ mod tests { assert_eq!( cake::Entity::update(cake::ActiveModel { + name: Set("Cheese Cake".to_owned()), + ..model.clone().into_active_model() + }) + .exec(&db) + .await, + Err(DbErr::RecordNotFound( + "None of the database rows are affected".to_owned() + )) + ); + + assert_eq!( + Update::one(cake::ActiveModel { name: Set("Cheese Cake".to_owned()), ..model.into_active_model() }) @@ -155,6 +189,15 @@ mod tests { )) ); + assert_eq!( + Update::many(cake::Entity) + .col_expr(cake::Column::Name, Expr::value("Cheese Cake".to_owned())) + .filter(cake::Column::Id.eq(2)) + .exec(&db) + .await, + Ok(UpdateResult { rows_affected: 0 }) + ); + assert_eq!( db.into_transaction_log(), vec![ @@ -173,6 +216,16 @@ mod tests { r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#, vec!["Cheese Cake".into(), 2i32.into()] ), + Transaction::from_sql_and_values( + DbBackend::Postgres, + r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#, + vec!["Cheese Cake".into(), 2i32.into()] + ), + Transaction::from_sql_and_values( + DbBackend::Postgres, + r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#, + vec!["Cheese Cake".into(), 2i32.into()] + ), ] ); From af93ea44ad970cd04476730b80cb613f7471ca8c Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 4 Oct 2021 12:10:06 +0800 Subject: [PATCH 06/21] Fix clippy warnings --- src/executor/query.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/executor/query.rs b/src/executor/query.rs index 0248fa5c..e6c2d124 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -126,12 +126,12 @@ macro_rules! try_getable_unsigned { ( $type: ty ) => { impl TryGetable for $type { fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + let _column = format!("{}{}", pre, col); match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) + row.try_get::, _>(_column.as_str()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(TryGetError::Null)) } @@ -142,13 +142,13 @@ macro_rules! try_getable_unsigned { #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) + row.try_get::, _>(_column.as_str()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(TryGetError::Null)) } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get(_column.as_str()).map_err(|e| { debug_print!("{:#?}", e.to_string()); TryGetError::Null }), @@ -162,12 +162,12 @@ macro_rules! try_getable_mysql { ( $type: ty ) => { impl TryGetable for $type { fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + let _column = format!("{}{}", pre, col); match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) + row.try_get::, _>(_column.as_str()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(TryGetError::Null)) } @@ -181,7 +181,7 @@ macro_rules! try_getable_mysql { } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get(_column.as_str()).map_err(|e| { debug_print!("{:#?}", e.to_string()); TryGetError::Null }), @@ -195,7 +195,7 @@ macro_rules! try_getable_postgres { ( $type: ty ) => { impl TryGetable for $type { fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { - let column = format!("{}{}", pre, col); + let _column = format!("{}{}", pre, col); match &res.row { #[cfg(feature = "sqlx-mysql")] QueryResultRow::SqlxMySql(_) => { @@ -204,7 +204,7 @@ macro_rules! try_getable_postgres { #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(row) => { use sqlx::Row; - row.try_get::, _>(column.as_str()) + row.try_get::, _>(_column.as_str()) .map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e))) .and_then(|opt| opt.ok_or(TryGetError::Null)) } @@ -214,7 +214,7 @@ macro_rules! try_getable_postgres { } #[cfg(feature = "mock")] #[allow(unused_variables)] - QueryResultRow::Mock(row) => row.try_get(column.as_str()).map_err(|e| { + QueryResultRow::Mock(row) => row.try_get(_column.as_str()).map_err(|e| { debug_print!("{:#?}", e.to_string()); TryGetError::Null }), From b74b1f343f6e8090029db381018aba30f71e764f Mon Sep 17 00:00:00 2001 From: "baoyachi. Aka Rust Hairy crabs" Date: Mon, 4 Oct 2021 12:57:34 +0800 Subject: [PATCH 07/21] Add debug_query and debug_query_stmt macro (#189) --- src/query/mod.rs | 2 + src/query/util.rs | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/query/util.rs diff --git a/src/query/mod.rs b/src/query/mod.rs index 54cc12dd..5d2be142 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -8,6 +8,7 @@ mod json; mod select; mod traits; mod update; +mod util; pub use combine::{SelectA, SelectB}; pub use delete::*; @@ -19,5 +20,6 @@ pub use json::*; pub use select::*; pub use traits::*; pub use update::*; +pub use util::*; pub use crate::{InsertResult, Statement, UpdateResult, Value, Values}; diff --git a/src/query/util.rs b/src/query/util.rs new file mode 100644 index 00000000..7e771f7c --- /dev/null +++ b/src/query/util.rs @@ -0,0 +1,112 @@ +use crate::{DatabaseConnection, DbBackend, QueryTrait, Statement}; + +#[derive(Debug)] +pub struct DebugQuery<'a, Q, T> { + pub query: &'a Q, + pub value: T, +} + +macro_rules! debug_query_build { + ($impl_obj:ty, $db_expr:expr) => { + impl<'a, Q> DebugQuery<'a, Q, $impl_obj> + where + Q: QueryTrait, + { + pub fn build(&self) -> Statement { + let func = $db_expr; + let db_backend = func(self); + self.query.build(db_backend) + } + } + }; +} + +debug_query_build!(DbBackend, |x: &DebugQuery<_, DbBackend>| x.value); +debug_query_build!(&DbBackend, |x: &DebugQuery<_, &DbBackend>| *x.value); +debug_query_build!( + DatabaseConnection, + |x: &DebugQuery<_, DatabaseConnection>| x.value.get_database_backend() +); +debug_query_build!( + &DatabaseConnection, + |x: &DebugQuery<_, &DatabaseConnection>| x.value.get_database_backend() +); + +/// Helper to get a `Statement` from an object that impl `QueryTrait`. +/// +/// # Example +/// +/// ``` +/// # #[cfg(feature = "mock")] +/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; +/// # +/// # let conn = MockDatabase::new(DbBackend::Postgres) +/// # .into_connection(); +/// # +/// use sea_orm::{entity::*, query::*, tests_cfg::cake, debug_query_stmt}; +/// +/// let c = cake::Entity::insert( +/// cake::ActiveModel { +/// id: ActiveValue::set(1), +/// name: ActiveValue::set("Apple Pie".to_owned()), +/// }); +/// +/// let raw_sql = debug_query_stmt!(&c, &conn).to_string(); +/// assert_eq!(raw_sql, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#); +/// +/// let raw_sql = debug_query_stmt!(&c, conn).to_string(); +/// assert_eq!(raw_sql, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#); +/// +/// let raw_sql = debug_query_stmt!(&c, DbBackend::MySql).to_string(); +/// assert_eq!(raw_sql, r#"INSERT INTO `cake` (`id`, `name`) VALUES (1, 'Apple Pie')"#); +/// +/// let raw_sql = debug_query_stmt!(&c, &DbBackend::MySql).to_string(); +/// assert_eq!(raw_sql, r#"INSERT INTO `cake` (`id`, `name`) VALUES (1, 'Apple Pie')"#); +/// +/// ``` +#[macro_export] +macro_rules! debug_query_stmt { + ($query:expr,$value:expr) => { + $crate::DebugQuery { + query: $query, + value: $value, + } + .build(); + }; +} + +/// Helper to get a raw SQL string from an object that impl `QueryTrait`. +/// +/// # Example +/// +/// ``` +/// # #[cfg(feature = "mock")] +/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; +/// # +/// # let conn = MockDatabase::new(DbBackend::Postgres) +/// # .into_connection(); +/// # +/// use sea_orm::{entity::*, query::*, tests_cfg::cake,debug_query}; +/// +/// let c = cake::Entity::insert( +/// cake::ActiveModel { +/// id: ActiveValue::set(1), +/// name: ActiveValue::set("Apple Pie".to_owned()), +/// }); +/// +/// let raw_sql = debug_query!(&c, &conn); +/// assert_eq!(raw_sql, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#); +/// +/// let raw_sql = debug_query!(&c, conn); +/// assert_eq!(raw_sql, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#); +/// +/// let raw_sql = debug_query!(&c, DbBackend::Sqlite); +/// assert_eq!(raw_sql, r#"INSERT INTO `cake` (`id`, `name`) VALUES (1, 'Apple Pie')"#); +/// +/// ``` +#[macro_export] +macro_rules! debug_query { + ($query:expr,$value:expr) => { + $crate::debug_query_stmt!($query, $value).to_string(); + }; +} From 4fd5d56dbf1bc95b6219219231e27098bfed9d9e Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 4 Oct 2021 13:13:36 +0800 Subject: [PATCH 08/21] cargo +nightly fmt --- src/docs.rs | 2 +- src/entity/model.rs | 10 ++++------ src/executor/query.rs | 2 +- src/executor/select.rs | 9 ++++----- src/lib.rs | 2 +- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/docs.rs b/src/docs.rs index bab054ef..4d1226c3 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -163,4 +163,4 @@ //! }, //! ) //! } -//! ``` \ No newline at end of file +//! ``` diff --git a/src/entity/model.rs b/src/entity/model.rs index 318b8e70..cd96b22e 100644 --- a/src/entity/model.rs +++ b/src/entity/model.rs @@ -69,12 +69,10 @@ pub trait FromQueryResult: Sized { /// /// assert_eq!( /// res, - /// vec![ - /// SelectResult { - /// name: "Chocolate Forest".to_owned(), - /// num_of_cakes: 2, - /// }, - /// ] + /// vec![SelectResult { + /// name: "Chocolate Forest".to_owned(), + /// num_of_cakes: 2, + /// },] /// ); /// # /// # Ok(()) diff --git a/src/executor/query.rs b/src/executor/query.rs index e6c2d124..a164e911 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -326,7 +326,7 @@ pub trait TryGetableMany: Sized { /// # ]]) /// # .into_connection(); /// # - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, EnumIter, DeriveIden, TryGetableMany}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DeriveIden, EnumIter, TryGetableMany}; /// /// #[derive(EnumIter, DeriveIden)] /// enum ResultCol { diff --git a/src/executor/select.rs b/src/executor/select.rs index bb386722..0db698f0 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -207,10 +207,7 @@ where /// .all(&db) /// .await?; /// - /// assert_eq!( - /// res, - /// vec![("Chocolate Forest".to_owned(), 2i64)] - /// ); + /// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]); /// # /// # Ok(()) /// # }); @@ -222,7 +219,9 @@ where /// vec![ /// r#"SELECT "cake"."name" AS "cake_name", COUNT("cake"."id") AS "num_of_cakes""#, /// r#"FROM "cake" GROUP BY "cake"."name""#, - /// ].join(" ").as_str(), + /// ] + /// .join(" ") + /// .as_str(), /// vec![] /// )] /// ); diff --git a/src/lib.rs b/src/lib.rs index 910044a5..6ddc442c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,6 +265,7 @@ )] mod database; +mod docs; mod driver; pub mod entity; pub mod error; @@ -273,7 +274,6 @@ pub mod query; pub mod schema; #[doc(hidden)] pub mod tests_cfg; -mod docs; mod util; pub use database::*; From 632290469b649d40b45760ff00f687a1467c5508 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 4 Oct 2021 21:01:02 +0800 Subject: [PATCH 09/21] Fixup --- src/query/util.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/query/util.rs b/src/query/util.rs index 7e771f7c..545f8376 100644 --- a/src/query/util.rs +++ b/src/query/util.rs @@ -1,4 +1,4 @@ -use crate::{DatabaseConnection, DbBackend, QueryTrait, Statement}; +use crate::{database::*, QueryTrait, Statement}; #[derive(Debug)] pub struct DebugQuery<'a, Q, T> { @@ -38,7 +38,7 @@ debug_query_build!( /// /// ``` /// # #[cfg(feature = "mock")] -/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; +/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, DbBackend}; /// # /// # let conn = MockDatabase::new(DbBackend::Postgres) /// # .into_connection(); @@ -81,7 +81,7 @@ macro_rules! debug_query_stmt { /// /// ``` /// # #[cfg(feature = "mock")] -/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; +/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, DbBackend}; /// # /// # let conn = MockDatabase::new(DbBackend::Postgres) /// # .into_connection(); From 19a572b72195c54814ae0755e09876b65089f3f7 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Mon, 4 Oct 2021 23:30:20 +0800 Subject: [PATCH 10/21] Escape rust keywords with `r#` raw identifier --- sea-orm-macros/src/derives/active_model.rs | 10 +-- sea-orm-macros/src/derives/entity_model.rs | 12 ++-- sea-orm-macros/src/derives/model.rs | 13 ++-- sea-orm-macros/src/util.rs | 40 ++++++++++++ src/tests_cfg/mod.rs | 2 + src/tests_cfg/rust_keyword.rs | 71 ++++++++++++++++++++++ 6 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 src/tests_cfg/rust_keyword.rs diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index 2227f09b..85bdcb69 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -1,4 +1,4 @@ -use crate::util::field_not_ignored; +use crate::util::{escape_rust_keyword, field_not_ignored, trim_starting_raw_identifier}; use heck::CamelCase; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; @@ -29,10 +29,10 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result) -> syn::Result { // if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct let mut table_name = None; @@ -60,8 +60,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res if let Fields::Named(fields) = item_struct.fields { for field in fields.named { if let Some(ident) = &field.ident { - let mut field_name = - Ident::new(&ident.to_string().to_case(Case::Pascal), Span::call_site()); + let mut field_name = Ident::new( + &trim_starting_raw_identifier(&ident).to_case(Case::Pascal), + Span::call_site(), + ); let mut nullable = false; let mut default_value = None; @@ -168,6 +170,8 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res field_name = enum_name; } + field_name = Ident::new(&escape_rust_keyword(field_name), Span::call_site()); + if ignore { continue; } else { diff --git a/sea-orm-macros/src/derives/model.rs b/sea-orm-macros/src/derives/model.rs index a43b487f..29a597b9 100644 --- a/sea-orm-macros/src/derives/model.rs +++ b/sea-orm-macros/src/derives/model.rs @@ -1,4 +1,7 @@ -use crate::{attributes::derive_attr, util::field_not_ignored}; +use crate::{ + attributes::derive_attr, + util::{escape_rust_keyword, field_not_ignored, trim_starting_raw_identifier}, +}; use heck::CamelCase; use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned}; @@ -43,10 +46,10 @@ impl DeriveModel { let column_idents = fields .iter() .map(|field| { - let mut ident = format_ident!( - "{}", - field.ident.as_ref().unwrap().to_string().to_camel_case() - ); + let ident = field.ident.as_ref().unwrap().to_string(); + let ident = trim_starting_raw_identifier(ident).to_camel_case(); + let ident = escape_rust_keyword(ident); + let mut ident = format_ident!("{}", &ident); for attr in field.attrs.iter() { if let Some(ident) = attr.path.get_ident() { if ident != "sea_orm" { diff --git a/sea-orm-macros/src/util.rs b/sea-orm-macros/src/util.rs index 7dda1087..8929e9e8 100644 --- a/sea-orm-macros/src/util.rs +++ b/sea-orm-macros/src/util.rs @@ -24,3 +24,43 @@ pub(crate) fn field_not_ignored(field: &Field) -> bool { } true } + +pub(crate) fn trim_starting_raw_identifier(string: T) -> String +where + T: ToString, +{ + string + .to_string() + .trim_start_matches(RAW_IDENTIFIER) + .to_string() +} + +pub(crate) fn escape_rust_keyword(string: T) -> String +where + T: ToString, +{ + let string = string.to_string(); + if is_rust_keyword(&string) { + format!("r#{}", string) + } else { + string + } +} + +pub(crate) fn is_rust_keyword(string: T) -> bool +where + T: ToString, +{ + let string = string.to_string(); + RUST_KEYWORDS.iter().any(|s| s.eq(&string)) +} + +pub(crate) const RAW_IDENTIFIER: &str = "r#"; + +pub(crate) const RUST_KEYWORDS: [&str; 52] = [ + "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", + "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", + "ref", "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "union", + "unsafe", "use", "where", "while", "abstract", "become", "box", "do", "final", "macro", + "override", "priv", "try", "typeof", "unsized", "virtual", "yield", +]; diff --git a/src/tests_cfg/mod.rs b/src/tests_cfg/mod.rs index 6bc86aed..d6c80b36 100644 --- a/src/tests_cfg/mod.rs +++ b/src/tests_cfg/mod.rs @@ -7,6 +7,7 @@ pub mod cake_filling_price; pub mod entity_linked; pub mod filling; pub mod fruit; +pub mod rust_keyword; pub mod vendor; pub use cake::Entity as Cake; @@ -15,4 +16,5 @@ pub use cake_filling::Entity as CakeFilling; pub use cake_filling_price::Entity as CakeFillingPrice; pub use filling::Entity as Filling; pub use fruit::Entity as Fruit; +pub use rust_keyword::Entity as RustKeyword; pub use vendor::Entity as Vendor; diff --git a/src/tests_cfg/rust_keyword.rs b/src/tests_cfg/rust_keyword.rs new file mode 100644 index 00000000..90671a34 --- /dev/null +++ b/src/tests_cfg/rust_keyword.rs @@ -0,0 +1,71 @@ +use crate as sea_orm; +use crate::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "rust_keyword")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub testing: i32, + pub rust: i32, + pub keywords: i32, + pub r#as: i32, + pub r#async: i32, + pub r#await: i32, + pub r#break: i32, + pub r#const: i32, + pub r#continue: i32, + pub r#dyn: i32, + pub r#else: i32, + pub r#enum: i32, + pub r#extern: i32, + pub r#false: i32, + pub r#fn: i32, + pub r#for: i32, + pub r#if: i32, + pub r#impl: i32, + pub r#in: i32, + pub r#let: i32, + pub r#loop: i32, + pub r#match: i32, + pub r#mod: i32, + pub r#move: i32, + pub r#mut: i32, + pub r#pub: i32, + pub r#ref: i32, + pub r#return: i32, + pub r#static: i32, + pub r#struct: i32, + pub r#trait: i32, + pub r#true: i32, + pub r#type: i32, + pub r#union: i32, + pub r#unsafe: i32, + pub r#use: i32, + pub r#where: i32, + pub r#while: i32, + pub r#abstract: i32, + pub r#become: i32, + pub r#box: i32, + pub r#do: i32, + pub r#final: i32, + pub r#macro: i32, + pub r#override: i32, + pub r#priv: i32, + pub r#try: i32, + pub r#typeof: i32, + pub r#unsized: i32, + pub r#virtual: i32, + pub r#yield: i32, +} + +#[derive(Debug, EnumIter)] +pub enum Relation {} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + unreachable!() + } +} + +impl ActiveModelBehavior for ActiveModel {} From f3f24320e9a8ffdbb166d5f5b92c4da513bcfd8f Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 5 Oct 2021 10:23:45 +0800 Subject: [PATCH 11/21] Add test cases --- src/tests_cfg/rust_keyword.rs | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/tests_cfg/rust_keyword.rs b/src/tests_cfg/rust_keyword.rs index 90671a34..299e9c6f 100644 --- a/src/tests_cfg/rust_keyword.rs +++ b/src/tests_cfg/rust_keyword.rs @@ -9,6 +9,7 @@ pub struct Model { pub testing: i32, pub rust: i32, pub keywords: i32, + pub r#raw_identifier: i32, pub r#as: i32, pub r#async: i32, pub r#await: i32, @@ -69,3 +70,66 @@ impl RelationTrait for Relation { } impl ActiveModelBehavior for ActiveModel {} + +#[cfg(test)] +mod tests { + use crate::tests_cfg::*; + use sea_query::Iden; + + #[test] + fn test_columns() { + assert_eq!(rust_keyword::Column::Id.to_string(), "id".to_owned()); + assert_eq!(rust_keyword::Column::Testing.to_string(), "testing".to_owned()); + assert_eq!(rust_keyword::Column::Rust.to_string(), "rust".to_owned()); + assert_eq!(rust_keyword::Column::Keywords.to_string(), "keywords".to_owned()); + assert_eq!(rust_keyword::Column::RawIdentifier.to_string(), "raw_identifier".to_owned()); + assert_eq!(rust_keyword::Column::As.to_string(), "as".to_owned()); + assert_eq!(rust_keyword::Column::Async.to_string(), "async".to_owned()); + assert_eq!(rust_keyword::Column::Await.to_string(), "await".to_owned()); + assert_eq!(rust_keyword::Column::Break.to_string(), "break".to_owned()); + assert_eq!(rust_keyword::Column::Const.to_string(), "const".to_owned()); + assert_eq!(rust_keyword::Column::Continue.to_string(), "continue".to_owned()); + assert_eq!(rust_keyword::Column::Dyn.to_string(), "dyn".to_owned()); + assert_eq!(rust_keyword::Column::Else.to_string(), "else".to_owned()); + assert_eq!(rust_keyword::Column::Enum.to_string(), "enum".to_owned()); + assert_eq!(rust_keyword::Column::Extern.to_string(), "extern".to_owned()); + assert_eq!(rust_keyword::Column::False.to_string(), "false".to_owned()); + assert_eq!(rust_keyword::Column::Fn.to_string(), "fn".to_owned()); + assert_eq!(rust_keyword::Column::For.to_string(), "for".to_owned()); + assert_eq!(rust_keyword::Column::If.to_string(), "if".to_owned()); + assert_eq!(rust_keyword::Column::Impl.to_string(), "impl".to_owned()); + assert_eq!(rust_keyword::Column::In.to_string(), "in".to_owned()); + assert_eq!(rust_keyword::Column::Let.to_string(), "let".to_owned()); + assert_eq!(rust_keyword::Column::Loop.to_string(), "loop".to_owned()); + assert_eq!(rust_keyword::Column::Match.to_string(), "match".to_owned()); + assert_eq!(rust_keyword::Column::Mod.to_string(), "mod".to_owned()); + assert_eq!(rust_keyword::Column::Move.to_string(), "move".to_owned()); + assert_eq!(rust_keyword::Column::Mut.to_string(), "mut".to_owned()); + assert_eq!(rust_keyword::Column::Pub.to_string(), "pub".to_owned()); + assert_eq!(rust_keyword::Column::Ref.to_string(), "ref".to_owned()); + assert_eq!(rust_keyword::Column::Return.to_string(), "return".to_owned()); + assert_eq!(rust_keyword::Column::Static.to_string(), "static".to_owned()); + assert_eq!(rust_keyword::Column::Struct.to_string(), "struct".to_owned()); + assert_eq!(rust_keyword::Column::Trait.to_string(), "trait".to_owned()); + assert_eq!(rust_keyword::Column::True.to_string(), "true".to_owned()); + assert_eq!(rust_keyword::Column::Type.to_string(), "type".to_owned()); + assert_eq!(rust_keyword::Column::Union.to_string(), "union".to_owned()); + assert_eq!(rust_keyword::Column::Unsafe.to_string(), "unsafe".to_owned()); + assert_eq!(rust_keyword::Column::Use.to_string(), "use".to_owned()); + assert_eq!(rust_keyword::Column::Where.to_string(), "where".to_owned()); + assert_eq!(rust_keyword::Column::While.to_string(), "while".to_owned()); + assert_eq!(rust_keyword::Column::Abstract.to_string(), "abstract".to_owned()); + assert_eq!(rust_keyword::Column::Become.to_string(), "become".to_owned()); + assert_eq!(rust_keyword::Column::Box.to_string(), "box".to_owned()); + assert_eq!(rust_keyword::Column::Do.to_string(), "do".to_owned()); + assert_eq!(rust_keyword::Column::Final.to_string(), "final".to_owned()); + assert_eq!(rust_keyword::Column::Macro.to_string(), "macro".to_owned()); + assert_eq!(rust_keyword::Column::Override.to_string(), "override".to_owned()); + assert_eq!(rust_keyword::Column::Priv.to_string(), "priv".to_owned()); + assert_eq!(rust_keyword::Column::Try.to_string(), "try".to_owned()); + assert_eq!(rust_keyword::Column::Typeof.to_string(), "typeof".to_owned()); + assert_eq!(rust_keyword::Column::Unsized.to_string(), "unsized".to_owned()); + assert_eq!(rust_keyword::Column::Virtual.to_string(), "virtual".to_owned()); + assert_eq!(rust_keyword::Column::Yield.to_string(), "yield".to_owned()); + } +} From 7779ac886eac1609fc1d44a96dea1f00919e2e77 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 5 Oct 2021 10:49:06 +0800 Subject: [PATCH 12/21] Escape rust keyword on codegen --- sea-orm-codegen/src/entity/column.rs | 5 +- sea-orm-codegen/src/entity/writer.rs | 58 ++++++++- sea-orm-codegen/src/lib.rs | 1 + sea-orm-codegen/src/util.rs | 27 +++++ sea-orm-codegen/tests/compact/rust_keyword.rs | 28 +++++ .../tests/expanded/rust_keyword.rs | 73 +++++++++++ src/tests_cfg/rust_keyword.rs | 114 +++++++++--------- 7 files changed, 246 insertions(+), 60 deletions(-) create mode 100644 sea-orm-codegen/src/util.rs create mode 100644 sea-orm-codegen/tests/compact/rust_keyword.rs create mode 100644 sea-orm-codegen/tests/expanded/rust_keyword.rs diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index 532f2e91..d3d47cb1 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -1,3 +1,4 @@ +use crate::util::escape_rust_keyword; use heck::{CamelCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; @@ -14,11 +15,11 @@ pub struct Column { impl Column { pub fn get_name_snake_case(&self) -> Ident { - format_ident!("{}", self.name.to_snake_case()) + format_ident!("{}", escape_rust_keyword(self.name.to_snake_case())) } pub fn get_name_camel_case(&self) -> Ident { - format_ident!("{}", self.name.to_camel_case()) + format_ident!("{}", escape_rust_keyword(self.name.to_camel_case())) } pub fn get_rs_type(&self) -> TokenStream { diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index 59f54537..5d064f88 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -597,18 +597,71 @@ mod tests { name: "id".to_owned(), }], }, + Entity { + table_name: "rust_keyword".to_owned(), + columns: vec![ + Column { + name: "id".to_owned(), + col_type: ColumnType::Integer(Some(11)), + auto_increment: true, + not_null: true, + unique: false, + }, + Column { + name: "testing".to_owned(), + col_type: ColumnType::Integer(Some(11)), + auto_increment: false, + not_null: true, + unique: false, + }, + Column { + name: "rust".to_owned(), + col_type: ColumnType::Integer(Some(11)), + auto_increment: false, + not_null: true, + unique: false, + }, + Column { + name: "keywords".to_owned(), + col_type: ColumnType::Integer(Some(11)), + auto_increment: false, + not_null: true, + unique: false, + }, + Column { + name: "type".to_owned(), + col_type: ColumnType::Integer(Some(11)), + auto_increment: false, + not_null: true, + unique: false, + }, + Column { + name: "typeof".to_owned(), + col_type: ColumnType::Integer(Some(11)), + auto_increment: false, + not_null: true, + unique: false, + }, + ], + relations: vec![], + conjunct_relations: vec![], + primary_keys: vec![PrimaryKey { + name: "id".to_owned(), + }], + }, ] } #[test] fn test_gen_expanded_code_blocks() -> io::Result<()> { let entities = setup(); - const ENTITY_FILES: [&str; 5] = [ + const ENTITY_FILES: [&str; 6] = [ include_str!("../../tests/expanded/cake.rs"), include_str!("../../tests/expanded/cake_filling.rs"), include_str!("../../tests/expanded/filling.rs"), include_str!("../../tests/expanded/fruit.rs"), include_str!("../../tests/expanded/vendor.rs"), + include_str!("../../tests/expanded/rust_keyword.rs"), ]; assert_eq!(entities.len(), ENTITY_FILES.len()); @@ -642,12 +695,13 @@ mod tests { #[test] fn test_gen_compact_code_blocks() -> io::Result<()> { let entities = setup(); - const ENTITY_FILES: [&str; 5] = [ + const ENTITY_FILES: [&str; 6] = [ include_str!("../../tests/compact/cake.rs"), include_str!("../../tests/compact/cake_filling.rs"), include_str!("../../tests/compact/filling.rs"), include_str!("../../tests/compact/fruit.rs"), include_str!("../../tests/compact/vendor.rs"), + include_str!("../../tests/compact/rust_keyword.rs"), ]; assert_eq!(entities.len(), ENTITY_FILES.len()); diff --git a/sea-orm-codegen/src/lib.rs b/sea-orm-codegen/src/lib.rs index 07e167bc..5e637de1 100644 --- a/sea-orm-codegen/src/lib.rs +++ b/sea-orm-codegen/src/lib.rs @@ -1,5 +1,6 @@ mod entity; mod error; +mod util; pub use entity::*; pub use error::*; diff --git a/sea-orm-codegen/src/util.rs b/sea-orm-codegen/src/util.rs new file mode 100644 index 00000000..e752215b --- /dev/null +++ b/sea-orm-codegen/src/util.rs @@ -0,0 +1,27 @@ +pub(crate) fn escape_rust_keyword(string: T) -> String +where + T: ToString, +{ + let string = string.to_string(); + if is_rust_keyword(&string) { + format!("r#{}", string) + } else { + string + } +} + +pub(crate) fn is_rust_keyword(string: T) -> bool +where + T: ToString, +{ + let string = string.to_string(); + RUST_KEYWORDS.iter().any(|s| s.eq(&string)) +} + +pub(crate) const RUST_KEYWORDS: [&str; 52] = [ + "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", + "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", + "ref", "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "union", + "unsafe", "use", "where", "while", "abstract", "become", "box", "do", "final", "macro", + "override", "priv", "try", "typeof", "unsized", "virtual", "yield", +]; diff --git a/sea-orm-codegen/tests/compact/rust_keyword.rs b/sea-orm-codegen/tests/compact/rust_keyword.rs new file mode 100644 index 00000000..9e51bafd --- /dev/null +++ b/sea-orm-codegen/tests/compact/rust_keyword.rs @@ -0,0 +1,28 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "rust_keyword")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub testing: i32, + pub rust: i32, + pub keywords: i32, + pub r#type: i32, + pub r#typeof: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("No RelationDef"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/tests/expanded/rust_keyword.rs b/sea-orm-codegen/tests/expanded/rust_keyword.rs new file mode 100644 index 00000000..5c24d71c --- /dev/null +++ b/sea-orm-codegen/tests/expanded/rust_keyword.rs @@ -0,0 +1,73 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "rust_keyword" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub testing: i32, + pub rust: i32, + pub keywords: i32, + pub r#type: i32, + pub r#typeof: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Testing, + Rust, + Keywords, + Type, + Typeof, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + type ValueType = i32; + + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Testing => ColumnType::Integer.def(), + Self::Rust => ColumnType::Integer.def(), + Self::Keywords => ColumnType::Integer.def(), + Self::Type => ColumnType::Integer.def(), + Self::Typeof => ColumnType::Integer.def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("No RelationDef"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/rust_keyword.rs b/src/tests_cfg/rust_keyword.rs index 299e9c6f..30052db6 100644 --- a/src/tests_cfg/rust_keyword.rs +++ b/src/tests_cfg/rust_keyword.rs @@ -60,12 +60,14 @@ pub struct Model { pub r#yield: i32, } -#[derive(Debug, EnumIter)] +#[derive(Copy, Clone, Debug, EnumIter)] pub enum Relation {} impl RelationTrait for Relation { fn def(&self) -> RelationDef { - unreachable!() + match self { + _ => panic!("No RelationDef"), + } } } @@ -73,63 +75,63 @@ impl ActiveModelBehavior for ActiveModel {} #[cfg(test)] mod tests { - use crate::tests_cfg::*; + use crate::tests_cfg::rust_keyword::*; use sea_query::Iden; #[test] fn test_columns() { - assert_eq!(rust_keyword::Column::Id.to_string(), "id".to_owned()); - assert_eq!(rust_keyword::Column::Testing.to_string(), "testing".to_owned()); - assert_eq!(rust_keyword::Column::Rust.to_string(), "rust".to_owned()); - assert_eq!(rust_keyword::Column::Keywords.to_string(), "keywords".to_owned()); - assert_eq!(rust_keyword::Column::RawIdentifier.to_string(), "raw_identifier".to_owned()); - assert_eq!(rust_keyword::Column::As.to_string(), "as".to_owned()); - assert_eq!(rust_keyword::Column::Async.to_string(), "async".to_owned()); - assert_eq!(rust_keyword::Column::Await.to_string(), "await".to_owned()); - assert_eq!(rust_keyword::Column::Break.to_string(), "break".to_owned()); - assert_eq!(rust_keyword::Column::Const.to_string(), "const".to_owned()); - assert_eq!(rust_keyword::Column::Continue.to_string(), "continue".to_owned()); - assert_eq!(rust_keyword::Column::Dyn.to_string(), "dyn".to_owned()); - assert_eq!(rust_keyword::Column::Else.to_string(), "else".to_owned()); - assert_eq!(rust_keyword::Column::Enum.to_string(), "enum".to_owned()); - assert_eq!(rust_keyword::Column::Extern.to_string(), "extern".to_owned()); - assert_eq!(rust_keyword::Column::False.to_string(), "false".to_owned()); - assert_eq!(rust_keyword::Column::Fn.to_string(), "fn".to_owned()); - assert_eq!(rust_keyword::Column::For.to_string(), "for".to_owned()); - assert_eq!(rust_keyword::Column::If.to_string(), "if".to_owned()); - assert_eq!(rust_keyword::Column::Impl.to_string(), "impl".to_owned()); - assert_eq!(rust_keyword::Column::In.to_string(), "in".to_owned()); - assert_eq!(rust_keyword::Column::Let.to_string(), "let".to_owned()); - assert_eq!(rust_keyword::Column::Loop.to_string(), "loop".to_owned()); - assert_eq!(rust_keyword::Column::Match.to_string(), "match".to_owned()); - assert_eq!(rust_keyword::Column::Mod.to_string(), "mod".to_owned()); - assert_eq!(rust_keyword::Column::Move.to_string(), "move".to_owned()); - assert_eq!(rust_keyword::Column::Mut.to_string(), "mut".to_owned()); - assert_eq!(rust_keyword::Column::Pub.to_string(), "pub".to_owned()); - assert_eq!(rust_keyword::Column::Ref.to_string(), "ref".to_owned()); - assert_eq!(rust_keyword::Column::Return.to_string(), "return".to_owned()); - assert_eq!(rust_keyword::Column::Static.to_string(), "static".to_owned()); - assert_eq!(rust_keyword::Column::Struct.to_string(), "struct".to_owned()); - assert_eq!(rust_keyword::Column::Trait.to_string(), "trait".to_owned()); - assert_eq!(rust_keyword::Column::True.to_string(), "true".to_owned()); - assert_eq!(rust_keyword::Column::Type.to_string(), "type".to_owned()); - assert_eq!(rust_keyword::Column::Union.to_string(), "union".to_owned()); - assert_eq!(rust_keyword::Column::Unsafe.to_string(), "unsafe".to_owned()); - assert_eq!(rust_keyword::Column::Use.to_string(), "use".to_owned()); - assert_eq!(rust_keyword::Column::Where.to_string(), "where".to_owned()); - assert_eq!(rust_keyword::Column::While.to_string(), "while".to_owned()); - assert_eq!(rust_keyword::Column::Abstract.to_string(), "abstract".to_owned()); - assert_eq!(rust_keyword::Column::Become.to_string(), "become".to_owned()); - assert_eq!(rust_keyword::Column::Box.to_string(), "box".to_owned()); - assert_eq!(rust_keyword::Column::Do.to_string(), "do".to_owned()); - assert_eq!(rust_keyword::Column::Final.to_string(), "final".to_owned()); - assert_eq!(rust_keyword::Column::Macro.to_string(), "macro".to_owned()); - assert_eq!(rust_keyword::Column::Override.to_string(), "override".to_owned()); - assert_eq!(rust_keyword::Column::Priv.to_string(), "priv".to_owned()); - assert_eq!(rust_keyword::Column::Try.to_string(), "try".to_owned()); - assert_eq!(rust_keyword::Column::Typeof.to_string(), "typeof".to_owned()); - assert_eq!(rust_keyword::Column::Unsized.to_string(), "unsized".to_owned()); - assert_eq!(rust_keyword::Column::Virtual.to_string(), "virtual".to_owned()); - assert_eq!(rust_keyword::Column::Yield.to_string(), "yield".to_owned()); + assert_eq!(Column::Id.to_string().as_str(), "id"); + assert_eq!(Column::Testing.to_string().as_str(), "testing"); + assert_eq!(Column::Rust.to_string().as_str(), "rust"); + assert_eq!(Column::Keywords.to_string().as_str(), "keywords"); + assert_eq!(Column::RawIdentifier.to_string().as_str(), "raw_identifier"); + assert_eq!(Column::As.to_string().as_str(), "as"); + assert_eq!(Column::Async.to_string().as_str(), "async"); + assert_eq!(Column::Await.to_string().as_str(), "await"); + assert_eq!(Column::Break.to_string().as_str(), "break"); + assert_eq!(Column::Const.to_string().as_str(), "const"); + assert_eq!(Column::Continue.to_string().as_str(), "continue"); + assert_eq!(Column::Dyn.to_string().as_str(), "dyn"); + assert_eq!(Column::Else.to_string().as_str(), "else"); + assert_eq!(Column::Enum.to_string().as_str(), "enum"); + assert_eq!(Column::Extern.to_string().as_str(), "extern"); + assert_eq!(Column::False.to_string().as_str(), "false"); + assert_eq!(Column::Fn.to_string().as_str(), "fn"); + assert_eq!(Column::For.to_string().as_str(), "for"); + assert_eq!(Column::If.to_string().as_str(), "if"); + assert_eq!(Column::Impl.to_string().as_str(), "impl"); + assert_eq!(Column::In.to_string().as_str(), "in"); + assert_eq!(Column::Let.to_string().as_str(), "let"); + assert_eq!(Column::Loop.to_string().as_str(), "loop"); + assert_eq!(Column::Match.to_string().as_str(), "match"); + assert_eq!(Column::Mod.to_string().as_str(), "mod"); + assert_eq!(Column::Move.to_string().as_str(), "move"); + assert_eq!(Column::Mut.to_string().as_str(), "mut"); + assert_eq!(Column::Pub.to_string().as_str(), "pub"); + assert_eq!(Column::Ref.to_string().as_str(), "ref"); + assert_eq!(Column::Return.to_string().as_str(), "return"); + assert_eq!(Column::Static.to_string().as_str(), "static"); + assert_eq!(Column::Struct.to_string().as_str(), "struct"); + assert_eq!(Column::Trait.to_string().as_str(), "trait"); + assert_eq!(Column::True.to_string().as_str(), "true"); + assert_eq!(Column::Type.to_string().as_str(), "type"); + assert_eq!(Column::Union.to_string().as_str(), "union"); + assert_eq!(Column::Unsafe.to_string().as_str(), "unsafe"); + assert_eq!(Column::Use.to_string().as_str(), "use"); + assert_eq!(Column::Where.to_string().as_str(), "where"); + assert_eq!(Column::While.to_string().as_str(), "while"); + assert_eq!(Column::Abstract.to_string().as_str(), "abstract"); + assert_eq!(Column::Become.to_string().as_str(), "become"); + assert_eq!(Column::Box.to_string().as_str(), "box"); + assert_eq!(Column::Do.to_string().as_str(), "do"); + assert_eq!(Column::Final.to_string().as_str(), "final"); + assert_eq!(Column::Macro.to_string().as_str(), "macro"); + assert_eq!(Column::Override.to_string().as_str(), "override"); + assert_eq!(Column::Priv.to_string().as_str(), "priv"); + assert_eq!(Column::Try.to_string().as_str(), "try"); + assert_eq!(Column::Typeof.to_string().as_str(), "typeof"); + assert_eq!(Column::Unsized.to_string().as_str(), "unsized"); + assert_eq!(Column::Virtual.to_string().as_str(), "virtual"); + assert_eq!(Column::Yield.to_string().as_str(), "yield"); } } From 8990261d703cbeecb6e1292efd7e58f50d060eaf Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 6 Oct 2021 12:28:46 +0800 Subject: [PATCH 13/21] Bind null custom types --- Cargo.toml | 2 +- tests/common/bakery_chain/metadata.rs | 4 ++-- tests/common/setup/schema.rs | 4 ++-- tests/parallel_tests.rs | 12 ++++++------ tests/uuid_tests.rs | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a4466152..b9675c38 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.2.4", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.16.5", features = ["thread-safe"] } +sea-query = { version = "^0.17.0", 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/tests/common/bakery_chain/metadata.rs b/tests/common/bakery_chain/metadata.rs index de513a22..2c297cd3 100644 --- a/tests/common/bakery_chain/metadata.rs +++ b/tests/common/bakery_chain/metadata.rs @@ -10,8 +10,8 @@ pub struct Model { pub key: String, pub value: String, pub bytes: Vec, - pub date: Date, - pub time: Time, + pub date: Option, + pub time: Option