commit
0deedddf28
10
.github/workflows/rust.yml
vendored
10
.github/workflows/rust.yml
vendored
@ -288,6 +288,7 @@ jobs:
|
|||||||
name: Examples
|
name: Examples
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
path: [basic, actix_example, actix4_example, axum_example, rocket_example]
|
path: [basic, actix_example, actix4_example, axum_example, rocket_example]
|
||||||
@ -312,6 +313,7 @@ jobs:
|
|||||||
if: ${{ (needs.init.outputs.run-partial == 'true' && needs.init.outputs.run-issues == 'true') }}
|
if: ${{ (needs.init.outputs.run-partial == 'true' && needs.init.outputs.run-issues == 'true') }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
path: [86, 249, 262, 319, 324]
|
path: [86, 249, 262, 319, 324]
|
||||||
@ -350,6 +352,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DATABASE_URL: "sqlite::memory:"
|
DATABASE_URL: "sqlite::memory:"
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
runtime: [async-std, actix, tokio]
|
runtime: [async-std, actix, tokio]
|
||||||
tls: [native-tls, rustls]
|
tls: [native-tls, rustls]
|
||||||
@ -392,6 +395,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DATABASE_URL: "mysql://root:@localhost"
|
DATABASE_URL: "mysql://root:@localhost"
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version: [8.0, 5.7]
|
version: [8.0, 5.7]
|
||||||
runtime: [async-std, actix, tokio]
|
runtime: [async-std, actix, tokio]
|
||||||
@ -452,8 +456,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DATABASE_URL: "mysql://root:@localhost"
|
DATABASE_URL: "mysql://root:@localhost"
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version: [10.6]
|
version: [10.6, 10.5, 10.4]
|
||||||
runtime: [async-std, actix, tokio]
|
runtime: [async-std, actix, tokio]
|
||||||
tls: [native-tls]
|
tls: [native-tls]
|
||||||
services:
|
services:
|
||||||
@ -512,8 +517,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DATABASE_URL: "postgres://root:root@localhost"
|
DATABASE_URL: "postgres://root:root@localhost"
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version: [13.3, 12.7, 11.12, 10.17, 9.6.22]
|
version: [13, 12, 11, 10, 9]
|
||||||
runtime: [tokio]
|
runtime: [tokio]
|
||||||
tls: [native-tls]
|
tls: [native-tls]
|
||||||
services:
|
services:
|
||||||
|
@ -45,6 +45,12 @@ pub trait ConnectionTrait<'a>: Sync {
|
|||||||
T: Send,
|
T: Send,
|
||||||
E: std::error::Error + Send;
|
E: std::error::Error + Send;
|
||||||
|
|
||||||
|
/// Check if the connection supports `RETURNING` syntax on insert and update
|
||||||
|
fn support_returning(&self) -> bool {
|
||||||
|
let db_backend = self.get_database_backend();
|
||||||
|
db_backend.support_returning()
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if the connection is a test connection for the Mock database
|
/// Check if the connection is a test connection for the Mock database
|
||||||
fn is_mock_connection(&self) -> bool {
|
fn is_mock_connection(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
@ -267,6 +267,11 @@ impl DbBackend {
|
|||||||
Self::Sqlite => Box::new(SqliteQueryBuilder),
|
Self::Sqlite => Box::new(SqliteQueryBuilder),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the database supports `RETURNING` syntax on insert and update
|
||||||
|
pub fn support_returning(&self) -> bool {
|
||||||
|
matches!(self, Self::Postgres)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
11
src/docs.rs
11
src/docs.rs
@ -3,7 +3,12 @@
|
|||||||
//! Relying on [SQLx](https://github.com/launchbadge/sqlx), SeaORM is a new library with async support from day 1.
|
//! Relying on [SQLx](https://github.com/launchbadge/sqlx), SeaORM is a new library with async support from day 1.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*, DatabaseConnection, DbBackend, MockDatabase, Transaction, IntoMockRow};
|
//! # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
//! #
|
||||||
|
//! # #[smol_potat::main]
|
||||||
|
//! # #[cfg(feature = "mock")]
|
||||||
|
//! # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
//! #
|
||||||
//! # let db = MockDatabase::new(DbBackend::Postgres)
|
//! # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
//! # .append_query_results(vec![
|
//! # .append_query_results(vec![
|
||||||
//! # vec![cake::Model {
|
//! # vec![cake::Model {
|
||||||
@ -19,7 +24,7 @@
|
|||||||
//! # .into_mock_row()],
|
//! # .into_mock_row()],
|
||||||
//! # ])
|
//! # ])
|
||||||
//! # .into_connection();
|
//! # .into_connection();
|
||||||
//! # let _: Result<(), DbErr> = smol::block_on(async {
|
//! #
|
||||||
//! // execute multiple queries in parallel
|
//! // execute multiple queries in parallel
|
||||||
//! let cakes_and_fruits: (Vec<cake::Model>, Vec<fruit::Model>) =
|
//! let cakes_and_fruits: (Vec<cake::Model>, Vec<fruit::Model>) =
|
||||||
//! futures::try_join!(Cake::find().all(&db), Fruit::find().all(&db))?;
|
//! futures::try_join!(Cake::find().all(&db), Fruit::find().all(&db))?;
|
||||||
@ -53,7 +58,7 @@
|
|||||||
//! # ]
|
//! # ]
|
||||||
//! # );
|
//! # );
|
||||||
//! # Ok(())
|
//! # Ok(())
|
||||||
//! # });
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! 2. Dynamic
|
//! 2. Dynamic
|
||||||
|
@ -19,7 +19,8 @@ pub struct MockDatabaseConnector;
|
|||||||
/// Defines a connection for the [MockDatabase]
|
/// Defines a connection for the [MockDatabase]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MockDatabaseConnection {
|
pub struct MockDatabaseConnection {
|
||||||
counter: AtomicUsize,
|
execute_counter: AtomicUsize,
|
||||||
|
query_counter: AtomicUsize,
|
||||||
mocker: Mutex<Box<dyn MockDatabaseTrait>>,
|
mocker: Mutex<Box<dyn MockDatabaseTrait>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +101,8 @@ impl MockDatabaseConnection {
|
|||||||
M: MockDatabaseTrait,
|
M: MockDatabaseTrait,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
counter: AtomicUsize::new(0),
|
execute_counter: AtomicUsize::new(0),
|
||||||
|
query_counter: AtomicUsize::new(0),
|
||||||
mocker: Mutex::new(Box::new(m)),
|
mocker: Mutex::new(Box::new(m)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,14 +119,14 @@ impl MockDatabaseConnection {
|
|||||||
/// Execute the SQL statement in the [MockDatabase]
|
/// Execute the SQL statement in the [MockDatabase]
|
||||||
pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
|
pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.execute_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
self.mocker.lock().unwrap().execute(counter, statement)
|
self.mocker.lock().unwrap().execute(counter, statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return one [QueryResult] if the query was successful
|
/// Return one [QueryResult] if the query was successful
|
||||||
pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
|
pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.query_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
let result = self.mocker.lock().unwrap().query(counter, statement)?;
|
let result = self.mocker.lock().unwrap().query(counter, statement)?;
|
||||||
Ok(result.into_iter().next())
|
Ok(result.into_iter().next())
|
||||||
}
|
}
|
||||||
@ -132,7 +134,7 @@ impl MockDatabaseConnection {
|
|||||||
/// Return all [QueryResult]s if the query was successful
|
/// Return all [QueryResult]s if the query was successful
|
||||||
pub fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
pub fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.query_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
self.mocker.lock().unwrap().query(counter, statement)
|
self.mocker.lock().unwrap().query(counter, statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +140,113 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Perform an `INSERT` operation on the ActiveModel
|
/// Perform an `INSERT` operation on the ActiveModel
|
||||||
|
///
|
||||||
|
/// # Example (Postgres)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 15,
|
||||||
|
/// # name: "Apple Pie".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
|
///
|
||||||
|
/// let apple = cake::ActiveModel {
|
||||||
|
/// name: Set("Apple Pie".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// apple.insert(&db).await?,
|
||||||
|
/// cake::Model {
|
||||||
|
/// id: 15,
|
||||||
|
/// name: "Apple Pie".to_owned(),
|
||||||
|
/// }
|
||||||
|
/// .into_active_model()
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::Postgres,
|
||||||
|
/// r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id", "name""#,
|
||||||
|
/// vec!["Apple Pie".into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example (MySQL)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::MySql)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 15,
|
||||||
|
/// # name: "Apple Pie".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .append_exec_results(vec![
|
||||||
|
/// # MockExecResult {
|
||||||
|
/// # last_insert_id: 15,
|
||||||
|
/// # rows_affected: 1,
|
||||||
|
/// # },
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
|
///
|
||||||
|
/// let apple = cake::ActiveModel {
|
||||||
|
/// name: Set("Apple Pie".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// apple.insert(&db).await?,
|
||||||
|
/// cake::Model {
|
||||||
|
/// id: 15,
|
||||||
|
/// name: "Apple Pie".to_owned(),
|
||||||
|
/// }
|
||||||
|
/// .into_active_model()
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![
|
||||||
|
/// Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::MySql,
|
||||||
|
/// r#"INSERT INTO `cake` (`name`) VALUES (?)"#,
|
||||||
|
/// vec!["Apple Pie".into()]
|
||||||
|
/// ),
|
||||||
|
/// Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::MySql,
|
||||||
|
/// r#"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = ? LIMIT ?"#,
|
||||||
|
/// vec![15.into(), 1u64.into()]
|
||||||
|
/// )
|
||||||
|
/// ]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
||||||
where
|
where
|
||||||
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
@ -147,20 +254,126 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
{
|
{
|
||||||
let am = ActiveModelBehavior::before_save(self, true)?;
|
let am = ActiveModelBehavior::before_save(self, true)?;
|
||||||
let res = <Self::Entity as EntityTrait>::insert(am).exec(db).await?;
|
let am = <Self::Entity as EntityTrait>::insert(am)
|
||||||
let found = <Self::Entity as EntityTrait>::find_by_id(res.last_insert_id)
|
.exec_with_returning(db)
|
||||||
.one(db)
|
|
||||||
.await?;
|
.await?;
|
||||||
let am = match found {
|
|
||||||
Some(model) => model.into_active_model(),
|
|
||||||
None => return Err(DbErr::Exec("Failed to find inserted item".to_owned())),
|
|
||||||
};
|
|
||||||
ActiveModelBehavior::after_save(am, true)
|
ActiveModelBehavior::after_save(am, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the `UPDATE` operation on an ActiveModel
|
/// Perform the `UPDATE` operation on an ActiveModel
|
||||||
|
///
|
||||||
|
/// # Example (Postgres)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![fruit::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Orange".to_owned(),
|
||||||
|
/// # cake_id: None,
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
|
||||||
|
///
|
||||||
|
/// let orange = fruit::ActiveModel {
|
||||||
|
/// id: Set(1),
|
||||||
|
/// name: Set("Orange".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// orange.update(&db).await?,
|
||||||
|
/// fruit::Model {
|
||||||
|
/// id: 1,
|
||||||
|
/// name: "Orange".to_owned(),
|
||||||
|
/// cake_id: None,
|
||||||
|
/// }
|
||||||
|
/// .into_active_model()
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::Postgres,
|
||||||
|
/// r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 RETURNING "id", "name", "cake_id""#,
|
||||||
|
/// vec!["Orange".into(), 1i32.into()]
|
||||||
|
/// )]);
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example (MySQL)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::MySql)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![fruit::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Orange".to_owned(),
|
||||||
|
/// # cake_id: None,
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .append_exec_results(vec![
|
||||||
|
/// # MockExecResult {
|
||||||
|
/// # last_insert_id: 0,
|
||||||
|
/// # rows_affected: 1,
|
||||||
|
/// # },
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
|
||||||
|
///
|
||||||
|
/// let orange = fruit::ActiveModel {
|
||||||
|
/// id: Set(1),
|
||||||
|
/// name: Set("Orange".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// orange.update(&db).await?,
|
||||||
|
/// fruit::Model {
|
||||||
|
/// id: 1,
|
||||||
|
/// name: "Orange".to_owned(),
|
||||||
|
/// cake_id: None,
|
||||||
|
/// }
|
||||||
|
/// .into_active_model()
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![
|
||||||
|
/// Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::MySql,
|
||||||
|
/// r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ?"#,
|
||||||
|
/// vec!["Orange".into(), 1i32.into()]
|
||||||
|
/// ),
|
||||||
|
/// Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::MySql,
|
||||||
|
/// r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
|
||||||
|
/// vec![1i32.into(), 1u64.into()]
|
||||||
|
/// )]);
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
||||||
where
|
where
|
||||||
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
{
|
{
|
||||||
@ -195,6 +408,48 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Delete an active model by its primary key
|
/// Delete an active model by its primary key
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_exec_results(vec![
|
||||||
|
/// # MockExecResult {
|
||||||
|
/// # last_insert_id: 0,
|
||||||
|
/// # rows_affected: 1,
|
||||||
|
/// # },
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
|
||||||
|
///
|
||||||
|
/// let orange = fruit::ActiveModel {
|
||||||
|
/// id: Set(3),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let delete_result = orange.delete(&db).await?;
|
||||||
|
///
|
||||||
|
/// assert_eq!(delete_result.rows_affected, 1);
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::Postgres,
|
||||||
|
/// r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
|
||||||
|
/// vec![3i32.into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
|
async fn delete<'a, C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
|
||||||
where
|
where
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
|
@ -95,8 +95,11 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![
|
/// # .append_query_results(vec![
|
||||||
@ -121,8 +124,6 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// cake::Entity::find().one(&db).await?,
|
/// cake::Entity::find().one(&db).await?,
|
||||||
/// Some(cake::Model {
|
/// Some(cake::Model {
|
||||||
@ -144,9 +145,6 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// },
|
/// },
|
||||||
/// ]
|
/// ]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -163,6 +161,9 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// ),
|
/// ),
|
||||||
/// ]
|
/// ]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn find() -> Select<Self> {
|
fn find() -> Select<Self> {
|
||||||
Select::new()
|
Select::new()
|
||||||
@ -173,8 +174,11 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![
|
/// # .append_query_results(vec![
|
||||||
@ -189,8 +193,6 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// cake::Entity::find_by_id(11).all(&db).await?,
|
/// cake::Entity::find_by_id(11).all(&db).await?,
|
||||||
/// vec![cake::Model {
|
/// vec![cake::Model {
|
||||||
@ -198,9 +200,6 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// name: "Sponge Cake".to_owned(),
|
/// name: "Sponge Cake".to_owned(),
|
||||||
/// }]
|
/// }]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -210,11 +209,17 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// vec![11i32.into()]
|
/// vec![11i32.into()]
|
||||||
/// )]
|
/// )]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
/// Find by composite key
|
/// Find by composite key
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![
|
/// # .append_query_results(vec![
|
||||||
@ -229,8 +234,6 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// cake_filling::Entity::find_by_id((2, 3)).all(&db).await?,
|
/// cake_filling::Entity::find_by_id((2, 3)).all(&db).await?,
|
||||||
/// vec![cake_filling::Model {
|
/// vec![cake_filling::Model {
|
||||||
@ -238,9 +241,6 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// filling_id: 3,
|
/// filling_id: 3,
|
||||||
/// }]
|
/// }]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -252,6 +252,9 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// ].join(" ").as_str(),
|
/// ].join(" ").as_str(),
|
||||||
/// vec![2i32.into(), 3i32.into()]
|
/// vec![2i32.into(), 3i32.into()]
|
||||||
/// )]);
|
/// )]);
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn find_by_id(values: <Self::PrimaryKey as PrimaryKeyTrait>::ValueType) -> Select<Self> {
|
fn find_by_id(values: <Self::PrimaryKey as PrimaryKeyTrait>::ValueType) -> Select<Self> {
|
||||||
let mut select = Self::find();
|
let mut select = Self::find();
|
||||||
@ -272,13 +275,55 @@ pub trait EntityTrait: EntityName {
|
|||||||
|
|
||||||
/// Insert an model into database
|
/// Insert an model into database
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example (Postgres)
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![vec![maplit::btreemap! {
|
||||||
|
/// # "id" => Into::<Value>::into(15),
|
||||||
|
/// # }]])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
|
///
|
||||||
|
/// let apple = cake::ActiveModel {
|
||||||
|
/// name: Set("Apple Pie".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
|
||||||
|
///
|
||||||
|
/// assert_eq!(dbg!(insert_result.last_insert_id), 15);
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::Postgres,
|
||||||
|
/// r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id""#,
|
||||||
|
/// vec!["Apple Pie".into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example (MySQL)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::MySql)
|
||||||
/// # .append_exec_results(vec![
|
/// # .append_exec_results(vec![
|
||||||
/// # MockExecResult {
|
/// # MockExecResult {
|
||||||
/// # last_insert_id: 15,
|
/// # last_insert_id: 15,
|
||||||
@ -294,21 +339,21 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// ..Default::default()
|
/// ..Default::default()
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
|
/// let insert_result = cake::Entity::insert(apple).exec(&db).await?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(insert_result.last_insert_id, 15);
|
/// assert_eq!(insert_result.last_insert_id, 15);
|
||||||
/// // assert_eq!(insert_result.rows_affected, 1);
|
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
/// vec![Transaction::from_sql_and_values(
|
/// vec![Transaction::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id""#, vec!["Apple Pie".into()]
|
/// DbBackend::MySql,
|
||||||
/// )]);
|
/// r#"INSERT INTO `cake` (`name`) VALUES (?)"#,
|
||||||
|
/// vec!["Apple Pie".into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn insert<A>(model: A) -> Insert<A>
|
fn insert<A>(model: A) -> Insert<A>
|
||||||
where
|
where
|
||||||
@ -319,13 +364,61 @@ pub trait EntityTrait: EntityName {
|
|||||||
|
|
||||||
/// Insert many models into database
|
/// Insert many models into database
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example (Postgres)
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![vec![maplit::btreemap! {
|
||||||
|
/// # "id" => Into::<Value>::into(28),
|
||||||
|
/// # }]])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
|
///
|
||||||
|
/// let apple = cake::ActiveModel {
|
||||||
|
/// name: Set("Apple Pie".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
/// let orange = cake::ActiveModel {
|
||||||
|
/// name: Set("Orange Scone".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let insert_result = cake::Entity::insert_many(vec![apple, orange])
|
||||||
|
/// .exec(&db)
|
||||||
|
/// .await?;
|
||||||
|
///
|
||||||
|
/// assert_eq!(insert_result.last_insert_id, 28);
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::Postgres,
|
||||||
|
/// r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id""#,
|
||||||
|
/// vec!["Apple Pie".into(), "Orange Scone".into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example (MySQL)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::MySql)
|
||||||
/// # .append_exec_results(vec![
|
/// # .append_exec_results(vec![
|
||||||
/// # MockExecResult {
|
/// # MockExecResult {
|
||||||
/// # last_insert_id: 28,
|
/// # last_insert_id: 28,
|
||||||
@ -345,22 +438,23 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// ..Default::default()
|
/// ..Default::default()
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
/// let insert_result = cake::Entity::insert_many(vec![apple, orange])
|
||||||
/// #
|
/// .exec(&db)
|
||||||
/// let insert_result = cake::Entity::insert_many(vec![apple, orange]).exec(&db).await?;
|
/// .await?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(insert_result.last_insert_id, 28);
|
/// assert_eq!(insert_result.last_insert_id, 28);
|
||||||
/// // assert_eq!(insert_result.rows_affected, 2);
|
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
/// vec![Transaction::from_sql_and_values(
|
/// vec![Transaction::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id""#,
|
/// DbBackend::MySql,
|
||||||
|
/// r#"INSERT INTO `cake` (`name`) VALUES (?), (?)"#,
|
||||||
/// vec!["Apple Pie".into(), "Orange Scone".into()]
|
/// vec!["Apple Pie".into(), "Orange Scone".into()]
|
||||||
/// )]);
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn insert_many<A, I>(models: I) -> Insert<A>
|
fn insert_many<A, I>(models: I) -> Insert<A>
|
||||||
where
|
where
|
||||||
@ -374,18 +468,22 @@ pub trait EntityTrait: EntityName {
|
|||||||
///
|
///
|
||||||
/// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
|
/// - To apply where conditions / filters, see [`QueryFilter`](crate::query::QueryFilter)
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example (Postgres)
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_exec_results(vec![
|
/// # .append_query_results(vec![
|
||||||
/// # MockExecResult {
|
/// # vec![fruit::Model {
|
||||||
/// # last_insert_id: 0,
|
/// # id: 1,
|
||||||
/// # rows_affected: 1,
|
/// # name: "Orange".to_owned(),
|
||||||
/// # },
|
/// # cake_id: None,
|
||||||
|
/// # }],
|
||||||
/// # ])
|
/// # ])
|
||||||
/// # .into_connection();
|
/// # .into_connection();
|
||||||
/// #
|
/// #
|
||||||
@ -397,25 +495,93 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// ..Default::default()
|
/// ..Default::default()
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// fruit::Entity::update(orange.clone())
|
/// fruit::Entity::update(orange.clone())
|
||||||
/// .filter(fruit::Column::Name.contains("orange"))
|
/// .filter(fruit::Column::Name.contains("orange"))
|
||||||
/// .exec(&db)
|
/// .exec(&db)
|
||||||
/// .await?,
|
/// .await?,
|
||||||
/// orange
|
/// fruit::Model {
|
||||||
|
/// id: 1,
|
||||||
|
/// name: "Orange".to_owned(),
|
||||||
|
/// cake_id: None,
|
||||||
|
/// }
|
||||||
|
/// .into_active_model(),
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
/// vec![Transaction::from_sql_and_values(
|
/// vec![Transaction::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 AND "fruit"."name" LIKE $3"#,
|
/// DbBackend::Postgres,
|
||||||
|
/// r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2 AND "fruit"."name" LIKE $3 RETURNING "id", "name", "cake_id""#,
|
||||||
/// vec!["Orange".into(), 1i32.into(), "%orange%".into()]
|
/// vec!["Orange".into(), 1i32.into(), "%orange%".into()]
|
||||||
/// )]);
|
/// )]);
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example (MySQL)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::MySql)
|
||||||
|
/// # .append_exec_results(vec![
|
||||||
|
/// # MockExecResult {
|
||||||
|
/// # last_insert_id: 0,
|
||||||
|
/// # rows_affected: 1,
|
||||||
|
/// # },
|
||||||
|
/// # ])
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![fruit::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Orange".to_owned(),
|
||||||
|
/// # cake_id: None,
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
|
/// #
|
||||||
|
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
|
||||||
|
///
|
||||||
|
/// let orange = fruit::ActiveModel {
|
||||||
|
/// id: Set(1),
|
||||||
|
/// name: Set("Orange".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// fruit::Entity::update(orange.clone())
|
||||||
|
/// .filter(fruit::Column::Name.contains("orange"))
|
||||||
|
/// .exec(&db)
|
||||||
|
/// .await?,
|
||||||
|
/// fruit::Model {
|
||||||
|
/// id: 1,
|
||||||
|
/// name: "Orange".to_owned(),
|
||||||
|
/// cake_id: None,
|
||||||
|
/// }
|
||||||
|
/// .into_active_model(),
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// db.into_transaction_log(),
|
||||||
|
/// vec![
|
||||||
|
/// Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::MySql,
|
||||||
|
/// r#"UPDATE `fruit` SET `name` = ? WHERE `fruit`.`id` = ? AND `fruit`.`name` LIKE ?"#,
|
||||||
|
/// vec!["Orange".into(), 1i32.into(), "%orange%".into()]
|
||||||
|
/// ),
|
||||||
|
/// Transaction::from_sql_and_values(
|
||||||
|
/// DbBackend::MySql,
|
||||||
|
/// r#"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`id` = ? LIMIT ?"#,
|
||||||
|
/// vec![1i32.into(), 1u64.into()]
|
||||||
|
/// )]);
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn update<A>(model: A) -> UpdateOne<A>
|
fn update<A>(model: A) -> UpdateOne<A>
|
||||||
where
|
where
|
||||||
@ -431,8 +597,11 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_exec_results(vec![
|
/// # .append_exec_results(vec![
|
||||||
@ -443,10 +612,13 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # ])
|
/// # ])
|
||||||
/// # .into_connection();
|
/// # .into_connection();
|
||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::{Expr, Value}};
|
/// use sea_orm::{
|
||||||
|
/// entity::*,
|
||||||
|
/// query::*,
|
||||||
|
/// sea_query::{Expr, Value},
|
||||||
|
/// tests_cfg::fruit,
|
||||||
|
/// };
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let update_result = fruit::Entity::update_many()
|
/// let update_result = fruit::Entity::update_many()
|
||||||
/// .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
|
/// .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
|
||||||
/// .filter(fruit::Column::Name.contains("Apple"))
|
/// .filter(fruit::Column::Name.contains("Apple"))
|
||||||
@ -454,15 +626,18 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// .await?;
|
/// .await?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(update_result.rows_affected, 5);
|
/// assert_eq!(update_result.rows_affected, 5);
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
/// vec![Transaction::from_sql_and_values(
|
/// vec![Transaction::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#, vec![Value::Int(None), "%Apple%".into()]
|
/// DbBackend::Postgres,
|
||||||
/// )]);
|
/// r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#,
|
||||||
|
/// vec![Value::Int(None), "%Apple%".into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn update_many() -> UpdateMany<Self> {
|
fn update_many() -> UpdateMany<Self> {
|
||||||
Update::many(Self::default())
|
Update::many(Self::default())
|
||||||
@ -475,8 +650,11 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_exec_results(vec![
|
/// # .append_exec_results(vec![
|
||||||
@ -494,20 +672,21 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// ..Default::default()
|
/// ..Default::default()
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
|
/// let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(delete_result.rows_affected, 1);
|
/// assert_eq!(delete_result.rows_affected, 1);
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
/// vec![Transaction::from_sql_and_values(
|
/// vec![Transaction::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#, vec![3i32.into()]
|
/// DbBackend::Postgres,
|
||||||
/// )]);
|
/// r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
|
||||||
|
/// vec![3i32.into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn delete<A>(model: A) -> DeleteOne<A>
|
fn delete<A>(model: A) -> DeleteOne<A>
|
||||||
where
|
where
|
||||||
@ -523,8 +702,11 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{entity::*, error::*, query::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_exec_results(vec![
|
/// # .append_exec_results(vec![
|
||||||
@ -533,27 +715,34 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # rows_affected: 5,
|
/// # rows_affected: 5,
|
||||||
/// # },
|
/// # },
|
||||||
/// # ])
|
/// # ])
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 15,
|
||||||
|
/// # name: "Apple Pie".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
/// # .into_connection();
|
/// # .into_connection();
|
||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::fruit};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let delete_result = fruit::Entity::delete_many()
|
/// let delete_result = fruit::Entity::delete_many()
|
||||||
/// .filter(fruit::Column::Name.contains("Apple"))
|
/// .filter(fruit::Column::Name.contains("Apple"))
|
||||||
/// .exec(&db)
|
/// .exec(&db)
|
||||||
/// .await?;
|
/// .await?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(delete_result.rows_affected, 5);
|
/// assert_eq!(delete_result.rows_affected, 5);
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
/// vec![Transaction::from_sql_and_values(
|
/// vec![Transaction::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#, vec!["%Apple%".into()]
|
/// DbBackend::Postgres,
|
||||||
/// )]);
|
/// r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#,
|
||||||
|
/// vec!["%Apple%".into()]
|
||||||
|
/// )]
|
||||||
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn delete_many() -> DeleteMany<Self> {
|
fn delete_many() -> DeleteMany<Self> {
|
||||||
Delete::many(Self::default())
|
Delete::many(Self::default())
|
||||||
|
@ -47,8 +47,11 @@ pub trait FromQueryResult: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![vec![
|
/// # .append_query_results(vec![vec![
|
||||||
@ -67,8 +70,6 @@ pub trait FromQueryResult: Sized {
|
|||||||
/// num_of_cakes: i32,
|
/// num_of_cakes: i32,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let res: Vec<SelectResult> = SelectResult::find_by_statement(Statement::from_sql_and_values(
|
/// let res: Vec<SelectResult> = SelectResult::find_by_statement(Statement::from_sql_and_values(
|
||||||
/// DbBackend::Postgres,
|
/// DbBackend::Postgres,
|
||||||
/// r#"SELECT "name", COUNT(*) AS "num_of_cakes" FROM "cake" GROUP BY("name")"#,
|
/// r#"SELECT "name", COUNT(*) AS "num_of_cakes" FROM "cake" GROUP BY("name")"#,
|
||||||
@ -85,8 +86,6 @@ pub trait FromQueryResult: Sized {
|
|||||||
/// },]
|
/// },]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
/// #
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
/// # assert_eq!(
|
/// # assert_eq!(
|
||||||
/// # db.into_transaction_log(),
|
/// # db.into_transaction_log(),
|
||||||
/// # vec![Transaction::from_sql_and_values(
|
/// # vec![Transaction::from_sql_and_values(
|
||||||
@ -95,6 +94,9 @@ pub trait FromQueryResult: Sized {
|
|||||||
/// # vec![]
|
/// # vec![]
|
||||||
/// # ),]
|
/// # ),]
|
||||||
/// # );
|
/// # );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn find_by_statement(stmt: Statement) -> SelectorRaw<SelectModel<Self>> {
|
fn find_by_statement(stmt: Statement) -> SelectorRaw<SelectModel<Self>> {
|
||||||
SelectorRaw::<SelectModel<Self>>::from_statement(stmt)
|
SelectorRaw::<SelectModel<Self>>::from_statement(stmt)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, ActiveModelTrait, ConnectionTrait, DbBackend, EntityTrait, Insert, PrimaryKeyTrait,
|
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Insert, IntoActiveModel,
|
||||||
Statement, TryFromU64,
|
Iterable, PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, TryFromU64,
|
||||||
|
};
|
||||||
|
use sea_query::{
|
||||||
|
Alias, Expr, FromValueTuple, Iden, InsertStatement, IntoColumnRef, Query, ValueTuple,
|
||||||
};
|
};
|
||||||
use sea_query::{FromValueTuple, InsertStatement, ValueTuple};
|
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
/// Defines a structure to perform INSERT operations in an ActiveModel
|
/// Defines a structure to perform INSERT operations in an ActiveModel
|
||||||
@ -39,18 +41,28 @@ where
|
|||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
let mut query = self.query;
|
let mut query = self.query;
|
||||||
if db.get_database_backend() == DbBackend::Postgres {
|
if db.support_returning() && <A::Entity as EntityTrait>::PrimaryKey::iter().count() > 0 {
|
||||||
use crate::{sea_query::Query, Iterable};
|
let mut returning = Query::select();
|
||||||
if <A::Entity as EntityTrait>::PrimaryKey::iter().count() > 0 {
|
returning.columns(
|
||||||
query.returning(
|
<A::Entity as EntityTrait>::PrimaryKey::iter().map(|c| c.into_column_ref()),
|
||||||
Query::select()
|
);
|
||||||
.columns(<A::Entity as EntityTrait>::PrimaryKey::iter())
|
query.returning(returning);
|
||||||
.take(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Inserter::<A>::new(self.primary_key, query).exec(db)
|
Inserter::<A>::new(self.primary_key, query).exec(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute an insert operation and return the inserted model (use `RETURNING` syntax if database supported)
|
||||||
|
pub fn exec_with_returning<'a, C>(
|
||||||
|
self,
|
||||||
|
db: &'a C,
|
||||||
|
) -> impl Future<Output = Result<A, DbErr>> + '_
|
||||||
|
where
|
||||||
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
|
C: ConnectionTrait<'a>,
|
||||||
|
A: 'a,
|
||||||
|
{
|
||||||
|
Inserter::<A>::new(self.primary_key, self.query).exec_with_returning(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Inserter<A>
|
impl<A> Inserter<A>
|
||||||
@ -75,6 +87,19 @@ where
|
|||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
exec_insert(self.primary_key, builder.build(&self.query), db)
|
exec_insert(self.primary_key, builder.build(&self.query), db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute an insert operation and return the inserted model (use `RETURNING` syntax if database supported)
|
||||||
|
pub fn exec_with_returning<'a, C>(
|
||||||
|
self,
|
||||||
|
db: &'a C,
|
||||||
|
) -> impl Future<Output = Result<A, DbErr>> + '_
|
||||||
|
where
|
||||||
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
|
C: ConnectionTrait<'a>,
|
||||||
|
A: 'a,
|
||||||
|
{
|
||||||
|
exec_insert_with_returning(self.primary_key, self.query, db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn exec_insert<'a, A, C>(
|
async fn exec_insert<'a, A, C>(
|
||||||
@ -88,16 +113,15 @@ where
|
|||||||
{
|
{
|
||||||
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
|
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
|
||||||
type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
|
type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
|
||||||
let last_insert_id_opt = match db.get_database_backend() {
|
let last_insert_id_opt = match db.support_returning() {
|
||||||
DbBackend::Postgres => {
|
true => {
|
||||||
use crate::{sea_query::Iden, Iterable};
|
|
||||||
let cols = PrimaryKey::<A>::iter()
|
let cols = PrimaryKey::<A>::iter()
|
||||||
.map(|col| col.to_string())
|
.map(|col| col.to_string())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let res = db.query_one(statement).await?.unwrap();
|
let res = db.query_one(statement).await?.unwrap();
|
||||||
res.try_get_many("", cols.as_ref()).ok()
|
res.try_get_many("", cols.as_ref()).ok()
|
||||||
}
|
}
|
||||||
_ => {
|
false => {
|
||||||
let last_insert_id = db.execute(statement).await?.last_insert_id();
|
let last_insert_id = db.execute(statement).await?.last_insert_id();
|
||||||
ValueTypeOf::<A>::try_from_u64(last_insert_id).ok()
|
ValueTypeOf::<A>::try_from_u64(last_insert_id).ok()
|
||||||
}
|
}
|
||||||
@ -111,3 +135,47 @@ where
|
|||||||
};
|
};
|
||||||
Ok(InsertResult { last_insert_id })
|
Ok(InsertResult { last_insert_id })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn exec_insert_with_returning<'a, A, C>(
|
||||||
|
primary_key: Option<ValueTuple>,
|
||||||
|
mut insert_statement: InsertStatement,
|
||||||
|
db: &'a C,
|
||||||
|
) -> Result<A, DbErr>
|
||||||
|
where
|
||||||
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
|
C: ConnectionTrait<'a>,
|
||||||
|
A: ActiveModelTrait,
|
||||||
|
{
|
||||||
|
let db_backend = db.get_database_backend();
|
||||||
|
let found = match db.support_returning() {
|
||||||
|
true => {
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
let insert_res =
|
||||||
|
exec_insert::<A, _>(primary_key, db_backend.build(&insert_statement), db).await?;
|
||||||
|
<A::Entity as EntityTrait>::find_by_id(insert_res.last_insert_id)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match found {
|
||||||
|
Some(model) => Ok(model.into_active_model()),
|
||||||
|
None => Err(DbErr::Exec("Failed to find inserted item".to_owned())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -96,12 +96,23 @@ where
|
|||||||
|
|
||||||
/// Fetch one page and increment the page counter
|
/// Fetch one page and increment the page counter
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, MockDatabase, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// # let owned_db = MockDatabase::new(DbBackend::Postgres).into_connection();
|
/// #
|
||||||
|
/// # let owned_db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Cake".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # vec![],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
/// # let db = &owned_db;
|
/// # let db = &owned_db;
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
/// let mut cake_pages = cake::Entity::find()
|
/// let mut cake_pages = cake::Entity::find()
|
||||||
@ -113,7 +124,7 @@ where
|
|||||||
/// }
|
/// }
|
||||||
/// #
|
/// #
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # });
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn fetch_and_next(&mut self) -> Result<Option<Vec<S::Item>>, DbErr> {
|
pub async fn fetch_and_next(&mut self) -> Result<Option<Vec<S::Item>>, DbErr> {
|
||||||
let vec = self.fetch().await?;
|
let vec = self.fetch().await?;
|
||||||
@ -124,12 +135,23 @@ where
|
|||||||
|
|
||||||
/// Convert self into an async stream
|
/// Convert self into an async stream
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, MockDatabase, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// # let owned_db = MockDatabase::new(DbBackend::Postgres).into_connection();
|
/// #
|
||||||
|
/// # let owned_db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Cake".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # vec![],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
/// # let db = &owned_db;
|
/// # let db = &owned_db;
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
/// #
|
||||||
/// use futures::TryStreamExt;
|
/// use futures::TryStreamExt;
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
@ -143,7 +165,7 @@ where
|
|||||||
/// }
|
/// }
|
||||||
/// #
|
/// #
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # });
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn into_stream(mut self) -> PinBoxStream<'db, Result<Vec<S::Item>, DbErr>> {
|
pub fn into_stream(mut self) -> PinBoxStream<'db, Result<Vec<S::Item>, DbErr>> {
|
||||||
Box::pin(stream! {
|
Box::pin(stream! {
|
||||||
|
@ -320,8 +320,11 @@ pub trait TryGetableMany: Sized {
|
|||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![vec![
|
/// # .append_query_results(vec![vec![
|
||||||
@ -344,8 +347,6 @@ pub trait TryGetableMany: Sized {
|
|||||||
/// NumOfCakes,
|
/// NumOfCakes,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let res: Vec<(String, i32)> =
|
/// let res: Vec<(String, i32)> =
|
||||||
/// <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
|
/// <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
|
||||||
/// DbBackend::Postgres,
|
/// DbBackend::Postgres,
|
||||||
@ -362,9 +363,6 @@ pub trait TryGetableMany: Sized {
|
|||||||
/// ("New York Cheese".to_owned(), 1),
|
/// ("New York Cheese".to_owned(), 1),
|
||||||
/// ]
|
/// ]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -374,6 +372,9 @@ pub trait TryGetableMany: Sized {
|
|||||||
/// vec![]
|
/// vec![]
|
||||||
/// ),]
|
/// ),]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
|
fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
|
||||||
where
|
where
|
||||||
|
@ -143,8 +143,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![vec![
|
/// # .append_query_results(vec![vec![
|
||||||
@ -164,8 +167,6 @@ where
|
|||||||
/// CakeName,
|
/// CakeName,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let res: Vec<String> = cake::Entity::find()
|
/// let res: Vec<String> = cake::Entity::find()
|
||||||
/// .select_only()
|
/// .select_only()
|
||||||
/// .column_as(cake::Column::Name, QueryAs::CakeName)
|
/// .column_as(cake::Column::Name, QueryAs::CakeName)
|
||||||
@ -177,9 +178,6 @@ where
|
|||||||
/// res,
|
/// res,
|
||||||
/// vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
|
/// vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -189,11 +187,17 @@ where
|
|||||||
/// vec![]
|
/// vec![]
|
||||||
/// )]
|
/// )]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
/// # #[cfg(all(feature = "mock", feature = "macros"))]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![vec![
|
/// # .append_query_results(vec![vec![
|
||||||
@ -212,8 +216,6 @@ where
|
|||||||
/// NumOfCakes,
|
/// NumOfCakes,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let res: Vec<(String, i64)> = cake::Entity::find()
|
/// let res: Vec<(String, i64)> = cake::Entity::find()
|
||||||
/// .select_only()
|
/// .select_only()
|
||||||
/// .column_as(cake::Column::Name, QueryAs::CakeName)
|
/// .column_as(cake::Column::Name, QueryAs::CakeName)
|
||||||
@ -224,9 +226,6 @@ where
|
|||||||
/// .await?;
|
/// .await?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]);
|
/// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]);
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -241,6 +240,9 @@ where
|
|||||||
/// vec![]
|
/// vec![]
|
||||||
/// )]
|
/// )]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
|
pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
|
||||||
where
|
where
|
||||||
@ -490,8 +492,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![vec![
|
/// # .append_query_results(vec![vec![
|
||||||
@ -514,8 +519,6 @@ where
|
|||||||
/// num_of_cakes: i32,
|
/// num_of_cakes: i32,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let res: Vec<SelectResult> = cake::Entity::find()
|
/// let res: Vec<SelectResult> = cake::Entity::find()
|
||||||
/// .from_raw_sql(Statement::from_sql_and_values(
|
/// .from_raw_sql(Statement::from_sql_and_values(
|
||||||
/// DbBackend::Postgres,
|
/// DbBackend::Postgres,
|
||||||
@ -539,9 +542,6 @@ where
|
|||||||
/// },
|
/// },
|
||||||
/// ]
|
/// ]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -551,6 +551,9 @@ where
|
|||||||
/// vec![]
|
/// vec![]
|
||||||
/// ),]
|
/// ),]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn into_model<M>(self) -> SelectorRaw<SelectModel<M>>
|
pub fn into_model<M>(self) -> SelectorRaw<SelectModel<M>>
|
||||||
where
|
where
|
||||||
@ -563,8 +566,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
|
/// #
|
||||||
|
/// # #[smol_potat::main]
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # #[cfg(feature = "mock")]
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
/// # .append_query_results(vec![vec![
|
/// # .append_query_results(vec![vec![
|
||||||
@ -581,8 +587,6 @@ where
|
|||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let res: Vec<serde_json::Value> = cake::Entity::find().from_raw_sql(
|
/// let res: Vec<serde_json::Value> = cake::Entity::find().from_raw_sql(
|
||||||
/// Statement::from_sql_and_values(
|
/// Statement::from_sql_and_values(
|
||||||
/// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![]
|
/// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![]
|
||||||
@ -605,9 +609,6 @@ where
|
|||||||
/// }),
|
/// }),
|
||||||
/// ]
|
/// ]
|
||||||
/// );
|
/// );
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -616,6 +617,9 @@ where
|
|||||||
/// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![]
|
/// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![]
|
||||||
/// ),
|
/// ),
|
||||||
/// ]);
|
/// ]);
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "with-json")]
|
#[cfg(feature = "with-json")]
|
||||||
pub fn into_json(self) -> SelectorRaw<SelectModel<JsonValue>> {
|
pub fn into_json(self) -> SelectorRaw<SelectModel<JsonValue>> {
|
||||||
@ -627,15 +631,23 @@ where
|
|||||||
|
|
||||||
/// Get an item from the Select query
|
/// Get an item from the Select query
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres).into_connection();
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Cake".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let _: Option<cake::Model> = cake::Entity::find()
|
/// let _: Option<cake::Model> = cake::Entity::find()
|
||||||
/// .from_raw_sql(Statement::from_sql_and_values(
|
/// .from_raw_sql(Statement::from_sql_and_values(
|
||||||
/// DbBackend::Postgres,
|
/// DbBackend::Postgres,
|
||||||
@ -644,9 +656,6 @@ where
|
|||||||
/// ))
|
/// ))
|
||||||
/// .one(&db)
|
/// .one(&db)
|
||||||
/// .await?;
|
/// .await?;
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -656,6 +665,9 @@ where
|
|||||||
/// vec![1.into()]
|
/// vec![1.into()]
|
||||||
/// ),]
|
/// ),]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
@ -670,15 +682,23 @@ where
|
|||||||
|
|
||||||
/// Get all items from the Select query
|
/// Get all items from the Select query
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[cfg(feature = "mock")]
|
/// # use sea_orm::{error::*, tests_cfg::*, *};
|
||||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
|
||||||
/// #
|
/// #
|
||||||
/// # let db = MockDatabase::new(DbBackend::Postgres).into_connection();
|
/// # #[smol_potat::main]
|
||||||
|
/// # #[cfg(feature = "mock")]
|
||||||
|
/// # pub async fn main() -> Result<(), DbErr> {
|
||||||
|
/// #
|
||||||
|
/// # let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
/// # .append_query_results(vec![
|
||||||
|
/// # vec![cake::Model {
|
||||||
|
/// # id: 1,
|
||||||
|
/// # name: "Cake".to_owned(),
|
||||||
|
/// # }],
|
||||||
|
/// # ])
|
||||||
|
/// # .into_connection();
|
||||||
/// #
|
/// #
|
||||||
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
/// use sea_orm::{entity::*, query::*, tests_cfg::cake};
|
||||||
///
|
///
|
||||||
/// # let _: Result<(), DbErr> = smol::block_on(async {
|
|
||||||
/// #
|
|
||||||
/// let _: Vec<cake::Model> = cake::Entity::find()
|
/// let _: Vec<cake::Model> = cake::Entity::find()
|
||||||
/// .from_raw_sql(Statement::from_sql_and_values(
|
/// .from_raw_sql(Statement::from_sql_and_values(
|
||||||
/// DbBackend::Postgres,
|
/// DbBackend::Postgres,
|
||||||
@ -687,9 +707,6 @@ where
|
|||||||
/// ))
|
/// ))
|
||||||
/// .all(&db)
|
/// .all(&db)
|
||||||
/// .await?;
|
/// .await?;
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # });
|
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// db.into_transaction_log(),
|
/// db.into_transaction_log(),
|
||||||
@ -699,6 +716,9 @@ where
|
|||||||
/// vec![]
|
/// vec![]
|
||||||
/// ),]
|
/// ),]
|
||||||
/// );
|
/// );
|
||||||
|
/// #
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, Statement, UpdateMany, UpdateOne,
|
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, IntoActiveModel,
|
||||||
|
Iterable, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne,
|
||||||
};
|
};
|
||||||
use sea_query::UpdateStatement;
|
use sea_query::{Alias, Expr, FromValueTuple, Query, UpdateStatement};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
/// Defines an update operation
|
/// Defines an update operation
|
||||||
@ -25,10 +26,11 @@ where
|
|||||||
/// Execute an update operation on an ActiveModel
|
/// Execute an update operation on an ActiveModel
|
||||||
pub async fn exec<'b, C>(self, db: &'b C) -> Result<A, DbErr>
|
pub async fn exec<'b, C>(self, db: &'b C) -> Result<A, DbErr>
|
||||||
where
|
where
|
||||||
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
C: ConnectionTrait<'b>,
|
C: ConnectionTrait<'b>,
|
||||||
{
|
{
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
exec_update_and_return_original(self.query, self.model, db).await
|
exec_update_and_return_updated(self.query, self.model, db).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,17 +80,61 @@ where
|
|||||||
Updater::new(query).exec(db).await
|
Updater::new(query).exec(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn exec_update_and_return_original<'a, A, C>(
|
async fn exec_update_and_return_updated<'a, A, C>(
|
||||||
query: UpdateStatement,
|
mut query: UpdateStatement,
|
||||||
model: A,
|
model: A,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
) -> Result<A, DbErr>
|
) -> Result<A, DbErr>
|
||||||
where
|
where
|
||||||
|
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
{
|
{
|
||||||
Updater::new(query).check_record_exists().exec(db).await?;
|
match db.support_returning() {
|
||||||
Ok(model)
|
true => {
|
||||||
|
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(
|
||||||
|
db_backend.build(&query),
|
||||||
|
)
|
||||||
|
.one(db)
|
||||||
|
.await?;
|
||||||
|
// If we got `None` then we are updating a row that does not exist.
|
||||||
|
match found {
|
||||||
|
Some(model) => Ok(model.into_active_model()),
|
||||||
|
None => Err(DbErr::RecordNotFound(
|
||||||
|
"None of the database rows are affected".to_owned(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
// If we updating a row that does not exist then an error will be thrown here.
|
||||||
|
Updater::new(query).check_record_exists().exec(db).await?;
|
||||||
|
let primary_key_value = match model.get_primary_key_value() {
|
||||||
|
Some(val) => FromValueTuple::from_value_tuple(val),
|
||||||
|
None => return Err(DbErr::Exec("Fail to get primary key from model".to_owned())),
|
||||||
|
};
|
||||||
|
let found = <A::Entity as EntityTrait>::find_by_id(primary_key_value)
|
||||||
|
.one(db)
|
||||||
|
.await?;
|
||||||
|
// If we cannot select the updated row from db by the cached primary key
|
||||||
|
match found {
|
||||||
|
Some(model) => Ok(model.into_active_model()),
|
||||||
|
None => Err(DbErr::Exec("Failed to find inserted item".to_owned())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn exec_update<'a, C>(
|
async fn exec_update<'a, C>(
|
||||||
@ -119,23 +165,16 @@ mod tests {
|
|||||||
#[smol_potat::test]
|
#[smol_potat::test]
|
||||||
async fn update_record_not_found_1() -> Result<(), DbErr> {
|
async fn update_record_not_found_1() -> Result<(), DbErr> {
|
||||||
let db = MockDatabase::new(DbBackend::Postgres)
|
let db = MockDatabase::new(DbBackend::Postgres)
|
||||||
|
.append_query_results(vec![
|
||||||
|
vec![cake::Model {
|
||||||
|
id: 1,
|
||||||
|
name: "Cheese Cake".to_owned(),
|
||||||
|
}],
|
||||||
|
vec![],
|
||||||
|
vec![],
|
||||||
|
vec![],
|
||||||
|
])
|
||||||
.append_exec_results(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,
|
|
||||||
},
|
|
||||||
MockExecResult {
|
|
||||||
last_insert_id: 0,
|
|
||||||
rows_affected: 0,
|
|
||||||
},
|
|
||||||
MockExecResult {
|
MockExecResult {
|
||||||
last_insert_id: 0,
|
last_insert_id: 0,
|
||||||
rows_affected: 0,
|
rows_affected: 0,
|
||||||
@ -217,22 +256,22 @@ mod tests {
|
|||||||
vec![
|
vec![
|
||||||
Transaction::from_sql_and_values(
|
Transaction::from_sql_and_values(
|
||||||
DbBackend::Postgres,
|
DbBackend::Postgres,
|
||||||
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#,
|
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2 RETURNING "id", "name""#,
|
||||||
vec!["Cheese Cake".into(), 1i32.into()]
|
vec!["Cheese Cake".into(), 1i32.into()]
|
||||||
),
|
),
|
||||||
Transaction::from_sql_and_values(
|
Transaction::from_sql_and_values(
|
||||||
DbBackend::Postgres,
|
DbBackend::Postgres,
|
||||||
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#,
|
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2 RETURNING "id", "name""#,
|
||||||
vec!["Cheese Cake".into(), 2i32.into()]
|
vec!["Cheese Cake".into(), 2i32.into()]
|
||||||
),
|
),
|
||||||
Transaction::from_sql_and_values(
|
Transaction::from_sql_and_values(
|
||||||
DbBackend::Postgres,
|
DbBackend::Postgres,
|
||||||
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#,
|
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2 RETURNING "id", "name""#,
|
||||||
vec!["Cheese Cake".into(), 2i32.into()]
|
vec!["Cheese Cake".into(), 2i32.into()]
|
||||||
),
|
),
|
||||||
Transaction::from_sql_and_values(
|
Transaction::from_sql_and_values(
|
||||||
DbBackend::Postgres,
|
DbBackend::Postgres,
|
||||||
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2"#,
|
r#"UPDATE "cake" SET "name" = $1 WHERE "cake"."id" = $2 RETURNING "id", "name""#,
|
||||||
vec!["Cheese Cake".into(), 2i32.into()]
|
vec!["Cheese Cake".into(), 2i32.into()]
|
||||||
),
|
),
|
||||||
Transaction::from_sql_and_values(
|
Transaction::from_sql_and_values(
|
||||||
|
69
tests/returning_tests.rs
Normal file
69
tests/returning_tests.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
pub mod common;
|
||||||
|
|
||||||
|
pub use common::{bakery_chain::*, setup::*, TestContext};
|
||||||
|
pub use sea_orm::{entity::prelude::*, *};
|
||||||
|
pub use sea_query::Query;
|
||||||
|
|
||||||
|
#[sea_orm_macros::test]
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "sqlx-mysql",
|
||||||
|
feature = "sqlx-sqlite",
|
||||||
|
feature = "sqlx-postgres"
|
||||||
|
))]
|
||||||
|
async fn main() -> Result<(), DbErr> {
|
||||||
|
use bakery::*;
|
||||||
|
|
||||||
|
let ctx = TestContext::new("returning_tests").await;
|
||||||
|
let db = &ctx.db;
|
||||||
|
let builder = db.get_database_backend();
|
||||||
|
|
||||||
|
let mut insert = Query::insert();
|
||||||
|
insert
|
||||||
|
.into_table(Entity)
|
||||||
|
.columns(vec![Column::Name, Column::ProfitMargin])
|
||||||
|
.values_panic(vec!["Bakery Shop".into(), 0.5.into()]);
|
||||||
|
|
||||||
|
let mut update = Query::update();
|
||||||
|
update
|
||||||
|
.table(Entity)
|
||||||
|
.values(vec![
|
||||||
|
(Column::Name, "Bakery Shop".into()),
|
||||||
|
(Column::ProfitMargin, 0.5.into()),
|
||||||
|
])
|
||||||
|
.and_where(Column::Id.eq(1));
|
||||||
|
|
||||||
|
let mut returning = Query::select();
|
||||||
|
returning.columns(vec![Column::Id, Column::Name, Column::ProfitMargin]);
|
||||||
|
|
||||||
|
create_tables(db).await?;
|
||||||
|
|
||||||
|
if db.support_returning() {
|
||||||
|
insert.returning(returning.clone());
|
||||||
|
let insert_res = db
|
||||||
|
.query_one(builder.build(&insert))
|
||||||
|
.await?
|
||||||
|
.expect("Insert failed with query_one");
|
||||||
|
let _id: i32 = insert_res.try_get("", "id")?;
|
||||||
|
let _name: String = insert_res.try_get("", "name")?;
|
||||||
|
let _profit_margin: f64 = insert_res.try_get("", "profit_margin")?;
|
||||||
|
|
||||||
|
update.returning(returning.clone());
|
||||||
|
let update_res = db
|
||||||
|
.query_one(builder.build(&update))
|
||||||
|
.await?
|
||||||
|
.expect("Update filed with query_one");
|
||||||
|
let _id: i32 = update_res.try_get("", "id")?;
|
||||||
|
let _name: String = update_res.try_get("", "name")?;
|
||||||
|
let _profit_margin: f64 = update_res.try_get("", "profit_margin")?;
|
||||||
|
} else {
|
||||||
|
let insert_res = db.execute(builder.build(&insert)).await?;
|
||||||
|
assert!(insert_res.rows_affected() > 0);
|
||||||
|
|
||||||
|
let update_res = db.execute(builder.build(&update)).await?;
|
||||||
|
assert!(update_res.rows_affected() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.delete().await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user