From 30f43b64c6151dfc5423ed8842db9138071b521d Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Mon, 8 Nov 2021 19:03:06 +0800 Subject: [PATCH] Fixup --- .github/workflows/rust.yml | 6 ++++- Cargo.toml | 2 +- src/database/db_connection.rs | 42 ++++++++++++++++++++++++++++++++--- src/database/transaction.rs | 6 +---- src/driver/sqlx_mysql.rs | 8 ++++--- src/executor/insert.rs | 33 ++++++++++++++++----------- src/executor/update.rs | 22 +++++++++++------- tests/returning_tests.rs | 37 ++++++++++++++++++++++++++++++ 8 files changed, 122 insertions(+), 34 deletions(-) create mode 100644 tests/returning_tests.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ad18203e..0734f3ac 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -350,6 +350,7 @@ jobs: env: DATABASE_URL: "sqlite::memory:" strategy: + fail-fast: false matrix: runtime: [async-std, actix, tokio] tls: [native-tls, rustls] @@ -392,6 +393,7 @@ jobs: env: DATABASE_URL: "mysql://root:@localhost" strategy: + fail-fast: false matrix: version: [8.0, 5.7] runtime: [async-std, actix, tokio] @@ -452,8 +454,9 @@ jobs: env: DATABASE_URL: "mysql://root:@localhost" strategy: + fail-fast: false matrix: - version: [10.6] + version: [10.7, 10.6, 10.5, 10.0, 5.5] runtime: [async-std, actix, tokio] tls: [native-tls] services: @@ -512,6 +515,7 @@ jobs: env: DATABASE_URL: "postgres://root:root@localhost" strategy: + fail-fast: false matrix: version: [13.3, 12.7, 11.12, 10.17, 9.6.22] runtime: [tokio] diff --git a/Cargo.toml b/Cargo.toml index 32589dea..46d8c617 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.1", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.18.0", git = "https://github.com/marlon-sousa/sea-query.git", branch = "extended-returning-support", features = ["thread-safe"] } +sea-query = { version = "^0.18.2", 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/database/db_connection.rs b/src/database/db_connection.rs index 9038dc20..59aaf5f2 100644 --- a/src/database/db_connection.rs +++ b/src/database/db_connection.rs @@ -19,9 +19,11 @@ pub enum DatabaseConnection { /// Create a MYSQL database connection and pool #[cfg(feature = "sqlx-mysql")] SqlxMySqlPoolConnection { - /// A SQLx MySQL pool + /// The SQLx MySQL pool conn: crate::SqlxMySqlPoolConnection, - /// A flag indicating whether `RETURNING` syntax is supported + /// The MySQL version + version: String, + /// The flag indicating whether `RETURNING` syntax is supported support_returning: bool, }, /// Create a PostgreSQL database connection and pool @@ -226,7 +228,7 @@ impl<'a> ConnectionTrait<'a> for DatabaseConnection { fn support_returning(&self) -> bool { match self { #[cfg(feature = "sqlx-mysql")] - DatabaseConnection::SqlxMySqlPoolConnection { .. } => false, + DatabaseConnection::SqlxMySqlPoolConnection { support_returning, .. } => *support_returning, #[cfg(feature = "sqlx-postgres")] DatabaseConnection::SqlxPostgresPoolConnection(_) => true, #[cfg(feature = "sqlx-sqlite")] @@ -264,6 +266,40 @@ impl DatabaseConnection { } } +impl DatabaseConnection { + /// Get database version + pub fn db_version(&self) -> String { + match self { + #[cfg(feature = "sqlx-mysql")] + DatabaseConnection::SqlxMySqlPoolConnection { version, .. } => version.to_string(), + // #[cfg(feature = "sqlx-postgres")] + // DatabaseConnection::SqlxPostgresPoolConnection(conn) => , + // #[cfg(feature = "sqlx-sqlite")] + // DatabaseConnection::SqlxSqlitePoolConnection(conn) => , + // #[cfg(feature = "mock")] + // DatabaseConnection::MockDatabaseConnection(conn) => , + DatabaseConnection::Disconnected => panic!("Disconnected"), + _ => unimplemented!(), + } + } + + /// Check if database supports `RETURNING` + pub fn db_support_returning(&self) -> bool { + match self { + #[cfg(feature = "sqlx-mysql")] + DatabaseConnection::SqlxMySqlPoolConnection { support_returning, .. } => *support_returning, + #[cfg(feature = "sqlx-postgres")] + DatabaseConnection::SqlxPostgresPoolConnection(_) => true, + // #[cfg(feature = "sqlx-sqlite")] + // DatabaseConnection::SqlxSqlitePoolConnection(conn) => , + // #[cfg(feature = "mock")] + // DatabaseConnection::MockDatabaseConnection(conn) => , + DatabaseConnection::Disconnected => panic!("Disconnected"), + _ => unimplemented!(), + } + } +} + impl DbBackend { /// Check if the URI is the same as the specified database backend. /// Returns true if they match. diff --git a/src/database/transaction.rs b/src/database/transaction.rs index 77394acd..474f5ede 100644 --- a/src/database/transaction.rs +++ b/src/database/transaction.rs @@ -349,11 +349,7 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction { } fn support_returning(&self) -> bool { - match self.backend { - DbBackend::MySql => false, - DbBackend::Postgres => true, - DbBackend::Sqlite => false, - } + panic!("FIXME: How?") } } diff --git a/src/driver/sqlx_mysql.rs b/src/driver/sqlx_mysql.rs index b8803edb..b66e1078 100644 --- a/src/driver/sqlx_mysql.rs +++ b/src/driver/sqlx_mysql.rs @@ -191,9 +191,9 @@ async fn into_db_connection(pool: MySqlPool) -> Result Result= 10 && ver_minor >= 5 - } + }; + (version, support_returning) } else { return Err(DbErr::Conn("Fail to parse MySQL version".to_owned())); }; Ok(DatabaseConnection::SqlxMySqlPoolConnection { conn, + version, support_returning, }) } diff --git a/src/executor/insert.rs b/src/executor/insert.rs index 9f371373..b5c2cf98 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -1,8 +1,10 @@ use crate::{ - error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, Insert, IntoActiveModel, Iterable, - PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, TryFromU64, + error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Insert, IntoActiveModel, + Iterable, PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, TryFromU64, +}; +use sea_query::{ + Alias, Expr, FromValueTuple, Iden, InsertStatement, IntoColumnRef, Query, ValueTuple, }; -use sea_query::{FromValueTuple, Iden, InsertStatement, IntoColumnRef, Returning, ValueTuple}; use std::{future::Future, marker::PhantomData}; /// Defines a structure to perform INSERT operations in an ActiveModel @@ -40,11 +42,10 @@ where // so that self is dropped before entering await let mut query = self.query; if db.support_returning() && ::PrimaryKey::iter().count() > 0 { - query.returning(Returning::Columns( - ::PrimaryKey::iter() - .map(|c| c.into_column_ref()) - .collect(), - )); + let mut returning = Query::select(); + returning + .columns(::PrimaryKey::iter().map(|c| c.into_column_ref())); + query.returning(returning); } Inserter::::new(self.primary_key, query).exec(db) } @@ -147,11 +148,17 @@ where let db_backend = db.get_database_backend(); let found = match db.support_returning() { true => { - insert_statement.returning(Returning::Columns( - ::Column::iter() - .map(|c| c.into_column_ref()) - .collect(), - )); + let mut returning = Query::select(); + returning.exprs(::Column::iter().map(|c| { + let col = Expr::col(c); + let col_def = ColumnTrait::def(&c); + let col_type = col_def.get_column_type(); + match col_type.get_enum_name() { + Some(_) => col.as_enum(Alias::new("text")), + None => col.into(), + } + })); + insert_statement.returning(returning); SelectorRaw::::Model>>::from_statement( db_backend.build(&insert_statement), ) diff --git a/src/executor/update.rs b/src/executor/update.rs index f83e8efb..9870b10d 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -1,8 +1,8 @@ use crate::{ - error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, IntoActiveModel, Iterable, - SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne, + error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, IntoActiveModel, + Iterable, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne, }; -use sea_query::{FromValueTuple, IntoColumnRef, Returning, UpdateStatement}; +use sea_query::{Alias, Expr, FromValueTuple, Query, UpdateStatement}; use std::future::Future; /// Defines an update operation @@ -92,11 +92,17 @@ where { match db.support_returning() { true => { - query.returning(Returning::Columns( - ::Column::iter() - .map(|c| c.into_column_ref()) - .collect(), - )); + let mut returning = Query::select(); + returning.exprs(::Column::iter().map(|c| { + let col = Expr::col(c); + let col_def = c.def(); + let col_type = col_def.get_column_type(); + match col_type.get_enum_name() { + Some(_) => col.as_enum(Alias::new("text")), + None => col.into(), + } + })); + query.returning(returning); let db_backend = db.get_database_backend(); let found: Option<::Model> = SelectorRaw::::Model>>::from_statement( diff --git a/tests/returning_tests.rs b/tests/returning_tests.rs new file mode 100644 index 00000000..0a1e02c9 --- /dev/null +++ b/tests/returning_tests.rs @@ -0,0 +1,37 @@ +pub mod common; + +pub use common::{features::*, setup::*, TestContext}; +use sea_orm::{entity::prelude::*, entity::*, DatabaseConnection}; + +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] +async fn main() -> Result<(), DbErr> { + let ctx = TestContext::new("returning_tests").await; + let db = &ctx.db; + + match db { + #[cfg(feature = "sqlx-mysql")] + DatabaseConnection::SqlxMySqlPoolConnection { .. } => { + let version = db.db_version(); + match version.as_str() { + "5.7.26" => assert!(!db.db_support_returning()), + _ => unimplemented!("Version {} is not included", version), + }; + }, + #[cfg(feature = "sqlx-postgres")] + DatabaseConnection::SqlxPostgresPoolConnection(_) => { + assert!(db.db_support_returning()); + }, + #[cfg(feature = "sqlx-sqlite")] + DatabaseConnection::SqlxSqlitePoolConnection(_) => {}, + _ => unreachable!(), + } + + ctx.delete().await; + + Ok(()) +}