Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning #292

Merged
merged 33 commits into from
Nov 17, 2021
Merged
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c5468eb
Use "marlon-sousa/sea-query"
billy1624 Nov 5, 2021
c39a3b8
Insert with returning for Postgres
billy1624 Nov 5, 2021
52ff943
Docs
billy1624 Nov 5, 2021
a977572
Update with returning for Postgres
billy1624 Nov 5, 2021
50605c7
FIXME: breaking behaviors
billy1624 Nov 5, 2021
6238736
Handle "None of the database rows are affected" for Postgres
billy1624 Nov 8, 2021
2f7cffa
Fix test cases
billy1624 Nov 8, 2021
732d080
Update docs
billy1624 Nov 8, 2021
0eafacc
Try returning on MariaDB
billy1624 Nov 8, 2021
80c0d69
Merge remote-tracking branch 'origin/master' into returning
billy1624 Nov 8, 2021
30f43b6
Fixup
billy1624 Nov 8, 2021
2f0ac4c
Fixup
billy1624 Nov 8, 2021
afdb1af
This will fail loll
billy1624 Nov 8, 2021
1723206
This will fail loll
billy1624 Nov 8, 2021
3e6423a
This will fail loll
billy1624 Nov 8, 2021
30a50ca
Try
billy1624 Nov 9, 2021
429b920
Fixup
billy1624 Nov 9, 2021
24fab66
Try
billy1624 Nov 9, 2021
8020ae1
Fixup
billy1624 Nov 9, 2021
533c3cf
Try
billy1624 Nov 9, 2021
ec637b2
Returning support for SQLite
billy1624 Nov 9, 2021
c1fae1b
Debug print
billy1624 Nov 9, 2021
cc035d7
Refactoring
billy1624 Nov 9, 2021
66c23c8
Revert MySQL & SQLite returning support
billy1624 Nov 10, 2021
257a893
Use `sea-query` master
billy1624 Nov 10, 2021
4d44827
Docs
billy1624 Nov 11, 2021
fd50ffd
Merge remote-tracking branch 'origin/master' into returning
billy1624 Nov 16, 2021
d5de8b1
Should fail
billy1624 Nov 16, 2021
9655805
Will fail, as expected
billy1624 Nov 16, 2021
4c147a2
Rewrite doctests
billy1624 Nov 16, 2021
f9d04fc
Hotfix - separate counter for mock exec & query
billy1624 Nov 16, 2021
7298fde
Rewrite doctests
billy1624 Nov 16, 2021
42404eb
Fixup
billy1624 Nov 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fixup
  • Loading branch information
billy1624 committed Nov 8, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 30f43b64c6151dfc5423ed8842db9138071b521d
6 changes: 5 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -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]
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 }
42 changes: 39 additions & 3 deletions src/database/db_connection.rs
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 1 addition & 5 deletions src/database/transaction.rs
Original file line number Diff line number Diff line change
@@ -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?")
}
}

8 changes: 5 additions & 3 deletions src/driver/sqlx_mysql.rs
Original file line number Diff line number Diff line change
@@ -191,9 +191,9 @@ async fn into_db_connection(pool: MySqlPool) -> Result<DatabaseConnection, DbErr
r#"SHOW VARIABLES LIKE "version""#.to_owned(),
))
.await?;
let support_returning = if let Some(query_result) = res {
let (version, support_returning) = if let Some(query_result) = res {
let version: String = query_result.try_get("", "Value")?;
if !version.contains("MariaDB") {
let support_returning = if !version.contains("MariaDB") {
// This is MySQL
false
} else {
@@ -213,12 +213,14 @@ async fn into_db_connection(pool: MySqlPool) -> Result<DatabaseConnection, DbErr
let ver_major = parse_captures!(1);
let ver_minor = parse_captures!(2);
ver_major >= 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,
})
}
33 changes: 20 additions & 13 deletions src/executor/insert.rs
Original file line number Diff line number Diff line change
@@ -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() && <A::Entity as EntityTrait>::PrimaryKey::iter().count() > 0 {
query.returning(Returning::Columns(
<A::Entity as EntityTrait>::PrimaryKey::iter()
.map(|c| c.into_column_ref())
.collect(),
));
let mut returning = Query::select();
returning
.columns(<A::Entity as EntityTrait>::PrimaryKey::iter().map(|c| c.into_column_ref()));
query.returning(returning);
}
Inserter::<A>::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(
<A::Entity as EntityTrait>::Column::iter()
.map(|c| c.into_column_ref())
.collect(),
));
let mut returning = Query::select();
returning.exprs(<A::Entity as EntityTrait>::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::<SelectModel<<A::Entity as EntityTrait>::Model>>::from_statement(
db_backend.build(&insert_statement),
)
22 changes: 14 additions & 8 deletions src/executor/update.rs
Original file line number Diff line number Diff line change
@@ -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(
<A::Entity as EntityTrait>::Column::iter()
.map(|c| c.into_column_ref())
.collect(),
));
let mut returning = Query::select();
returning.exprs(<A::Entity as EntityTrait>::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<<A::Entity as EntityTrait>::Model> =
SelectorRaw::<SelectModel<<A::Entity as EntityTrait>::Model>>::from_statement(
37 changes: 37 additions & 0 deletions tests/returning_tests.rs
Original file line number Diff line number Diff line change
@@ -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(())
}