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

Insert & Update Return Model #339

Merged
merged 7 commits into from
Dec 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ let mut pear: fruit::ActiveModel = pear.unwrap().into();
pear.name = Set("Sweet pear".to_owned());

// update one
let pear: fruit::ActiveModel = pear.update(db).await?;
let pear: fruit::Model = pear.update(db).await?;

// update many: UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."name" LIKE '%Apple%'
Fruit::update_many()
Expand All @@ -142,7 +142,7 @@ let banana = fruit::ActiveModel {
};

// create, because primary key `id` is `Unset`
let mut banana = banana.save(db).await?;
let mut banana = banana.save(db).await?.into_active_model();

banana.name = Set("Banana Mongo".to_owned());

Expand Down
6 changes: 3 additions & 3 deletions examples/basic/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub async fn insert_and_update(db: &DbConn) -> Result<(), DbErr> {
let mut pear: fruit::ActiveModel = pear.unwrap().into();
pear.name = Set("Sweet pear".to_owned());

let pear: fruit::ActiveModel = pear.update(db).await?;
let pear: fruit::Model = pear.update(db).await?;

println!();
println!("Updated: {:?}\n", pear);
Expand All @@ -46,14 +46,14 @@ pub async fn save_active_model(db: &DbConn) -> Result<(), DbErr> {
name: Set("Banana".to_owned()),
..Default::default()
};
let mut banana = banana.save(db).await?;
let mut banana: fruit::ActiveModel = banana.save(db).await?.into_active_model();

println!();
println!("Inserted: {:?}\n", banana);

banana.name = Set("Banana Mongo".to_owned());

let banana = banana.save(db).await?;
let banana: fruit::ActiveModel = banana.save(db).await?.into_active_model();

println!();
println!("Updated: {:?}\n", banana);
Expand Down
32 changes: 15 additions & 17 deletions src/entity/active_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ pub trait ActiveModelTrait: Clone + Debug {
/// id: 15,
/// name: "Apple Pie".to_owned(),
/// }
/// .into_active_model()
/// );
///
/// assert_eq!(
Expand Down Expand Up @@ -225,7 +224,6 @@ pub trait ActiveModelTrait: Clone + Debug {
/// id: 15,
/// name: "Apple Pie".to_owned(),
/// }
/// .into_active_model()
/// );
///
/// assert_eq!(
Expand All @@ -247,17 +245,17 @@ pub trait ActiveModelTrait: Clone + Debug {
/// # Ok(())
/// # }
/// ```
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
async fn insert<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
where
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
Self: ActiveModelBehavior + 'a,
C: ConnectionTrait<'a>,
{
let am = ActiveModelBehavior::before_save(self, true)?;
let am = <Self::Entity as EntityTrait>::insert(am)
let model = <Self::Entity as EntityTrait>::insert(am)
.exec_with_returning(db)
.await?;
ActiveModelBehavior::after_save(am, true)
Self::after_save(model, true)
}

/// Perform the `UPDATE` operation on an ActiveModel
Expand Down Expand Up @@ -296,7 +294,6 @@ pub trait ActiveModelTrait: Clone + Debug {
/// name: "Orange".to_owned(),
/// cake_id: None,
/// }
/// .into_active_model()
/// );
///
/// assert_eq!(
Expand Down Expand Up @@ -351,7 +348,6 @@ pub trait ActiveModelTrait: Clone + Debug {
/// name: "Orange".to_owned(),
/// cake_id: None,
/// }
/// .into_active_model()
/// );
///
/// assert_eq!(
Expand All @@ -371,26 +367,26 @@ pub trait ActiveModelTrait: Clone + Debug {
/// # Ok(())
/// # }
/// ```
async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
async fn update<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
where
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
Self: ActiveModelBehavior + 'a,
C: ConnectionTrait<'a>,
{
let am = ActiveModelBehavior::before_save(self, false)?;
let am = Self::Entity::update(am).exec(db).await?;
ActiveModelBehavior::after_save(am, false)
let model: <Self::Entity as EntityTrait>::Model = Self::Entity::update(am).exec(db).await?;
Self::after_save(model, false)
}

/// Insert the model if primary key is unset, update otherwise.
/// Only works if the entity has auto increment primary key.
async fn save<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
async fn save<'a, C>(self, db: &'a C) -> Result<<Self::Entity as EntityTrait>::Model, DbErr>
where
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
Self: ActiveModelBehavior + 'a,
C: ConnectionTrait<'a>,
{
let mut am = self;
let am = self;
let mut is_update = true;
for key in <Self::Entity as EntityTrait>::PrimaryKey::iter() {
let col = key.into_column();
Expand All @@ -400,11 +396,10 @@ pub trait ActiveModelTrait: Clone + Debug {
}
}
if !is_update {
am = am.insert(db).await?;
am.insert(db).await
} else {
am = am.update(db).await?;
am.update(db).await
}
Ok(am)
}

/// Delete an active model by its primary key
Expand Down Expand Up @@ -503,8 +498,11 @@ pub trait ActiveModelBehavior: ActiveModelTrait {
}

/// Will be called after saving
fn after_save(self, insert: bool) -> Result<Self, DbErr> {
Ok(self)
fn after_save(
model: <Self::Entity as EntityTrait>::Model,
insert: bool,
) -> Result<<Self::Entity as EntityTrait>::Model, DbErr> {
Ok(model)
}

/// Will be called before deleting
Expand Down
2 changes: 0 additions & 2 deletions src/entity/base_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,6 @@ pub trait EntityTrait: EntityName {
/// name: "Orange".to_owned(),
/// cake_id: None,
/// }
/// .into_active_model(),
/// );
///
/// assert_eq!(
Expand Down Expand Up @@ -563,7 +562,6 @@ pub trait EntityTrait: EntityName {
/// name: "Orange".to_owned(),
/// cake_id: None,
/// }
/// .into_active_model(),
/// );
///
/// assert_eq!(
Expand Down
10 changes: 5 additions & 5 deletions src/executor/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ where
pub fn exec_with_returning<'a, C>(
self,
db: &'a C,
) -> impl Future<Output = Result<A, DbErr>> + '_
) -> impl Future<Output = Result<<A::Entity as EntityTrait>::Model, DbErr>> + '_
where
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
C: ConnectionTrait<'a>,
Expand Down Expand Up @@ -92,13 +92,13 @@ where
pub fn exec_with_returning<'a, C>(
self,
db: &'a C,
) -> impl Future<Output = Result<A, DbErr>> + '_
) -> impl Future<Output = Result<<A::Entity as EntityTrait>::Model, DbErr>> + '_
where
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
C: ConnectionTrait<'a>,
A: 'a,
{
exec_insert_with_returning(self.primary_key, self.query, db)
exec_insert_with_returning::<A, _>(self.primary_key, self.query, db)
}
}

Expand Down Expand Up @@ -140,7 +140,7 @@ async fn exec_insert_with_returning<'a, A, C>(
primary_key: Option<ValueTuple>,
mut insert_statement: InsertStatement,
db: &'a C,
) -> Result<A, DbErr>
) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
where
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
C: ConnectionTrait<'a>,
Expand Down Expand Up @@ -175,7 +175,7 @@ where
}
};
match found {
Some(model) => Ok(model.into_active_model()),
Some(model) => Ok(model),
None => Err(DbErr::Exec("Failed to find inserted item".to_owned())),
}
}
15 changes: 6 additions & 9 deletions src/executor/update.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, IntoActiveModel,
Iterable, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne,
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, Iterable, SelectModel,
SelectorRaw, Statement, UpdateMany, UpdateOne,
};
use sea_query::{Alias, Expr, FromValueTuple, Query, UpdateStatement};
use std::future::Future;
Expand All @@ -24,9 +24,8 @@ where
A: ActiveModelTrait,
{
/// 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::Entity as EntityTrait>::Model, DbErr>
where
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
C: ConnectionTrait<'b>,
{
// so that self is dropped before entering await
Expand Down Expand Up @@ -84,9 +83,8 @@ async fn exec_update_and_return_updated<'a, A, C>(
mut query: UpdateStatement,
model: A,
db: &'a C,
) -> Result<A, DbErr>
) -> Result<<A::Entity as EntityTrait>::Model, DbErr>
where
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
A: ActiveModelTrait,
C: ConnectionTrait<'a>,
{
Expand All @@ -112,7 +110,7 @@ where
.await?;
// If we got `None` then we are updating a row that does not exist.
match found {
Some(model) => Ok(model.into_active_model()),
Some(model) => Ok(model),
None => Err(DbErr::RecordNotFound(
"None of the database rows are affected".to_owned(),
)),
Expand All @@ -130,7 +128,7 @@ where
.await?;
// If we cannot select the updated row from db by the cached primary key
match found {
Some(model) => Ok(model.into_active_model()),
Some(model) => Ok(model),
None => Err(DbErr::Exec("Failed to find inserted item".to_owned())),
}
}
Expand Down Expand Up @@ -196,7 +194,6 @@ mod tests {
id: 1,
name: "Cheese Cake".to_owned(),
}
.into_active_model()
);

let model = cake::Model {
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@
//! pear.name = Set("Sweet pear".to_owned());
//!
//! // update one
//! let pear: fruit::ActiveModel = pear.update(db).await?;
//! let pear: fruit::Model = pear.update(db).await?;
//!
//! // update many: UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."name" LIKE '%Apple%'
//! Fruit::update_many()
Expand All @@ -207,7 +207,7 @@
//! };
//!
//! // create, because primary key `id` is `Unset`
//! let mut banana = banana.save(db).await?;
//! let mut banana = banana.save(db).await?.into_active_model();
//!
//! banana.name = Set("Banana Mongo".to_owned());
//!
Expand Down
36 changes: 18 additions & 18 deletions tests/active_enum_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,25 @@ async fn main() -> Result<(), DbErr> {
pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
use active_enum::*;

let am = ActiveModel {
category: Set(None),
color: Set(None),
tea: Set(None),
..Default::default()
}
.insert(db)
.await?;
let model = Model {
id: 1,
category: None,
color: None,
tea: None,
};

let model = Entity::find().one(db).await?.unwrap();
assert_eq!(
model,
Model {
id: 1,
category: None,
color: None,
tea: None,
ActiveModel {
category: Set(None),
color: Set(None),
tea: Set(None),
..Default::default()
}
.insert(db)
.await?
);
assert_eq!(model, Entity::find().one(db).await?.unwrap());
assert_eq!(
model,
Entity::find()
Expand All @@ -58,11 +58,11 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
.unwrap()
);

let am = ActiveModel {
let _ = ActiveModel {
category: Set(Some(Category::Big)),
color: Set(Some(Color::Black)),
tea: Set(Some(Tea::EverydayTea)),
..am
..model.into_active_model()
}
.save(db)
.await?;
Expand All @@ -89,7 +89,7 @@ pub async fn insert_active_enum(db: &DatabaseConnection) -> Result<(), DbErr> {
.unwrap()
);

let res = am.delete(db).await?;
let res = model.into_active_model().delete(db).await?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a wrapper method to Model so it can be
model.delete(db)


assert_eq!(res.rows_affected, 1);
assert_eq!(Entity::find().one(db).await?, None);
Expand Down Expand Up @@ -146,7 +146,7 @@ pub async fn insert_active_enum_child(db: &DatabaseConnection) -> Result<(), DbE
category: Set(Some(Category::Big)),
color: Set(Some(Color::Black)),
tea: Set(Some(Tea::EverydayTea)),
..am
..am.into_active_model()
}
.save(db)
.await?;
Expand Down
6 changes: 3 additions & 3 deletions tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ async fn crud_cake(db: &DbConn) -> Result<(), DbErr> {
..Default::default()
};

let mut apple = apple.save(db).await?;
let mut apple = apple.save(db).await?.into_active_model();

println!();
println!("Inserted: {:?}", apple);

assert_eq!(
apple,
cake::ActiveModel {
id: Set(1),
name: Set("Apple Pie".to_owned()),
},
apple
}
);

apple.name = Set("Lemon Tart".to_owned());
Expand Down
Loading