๐ We are pleased to release SeaORM 0.3.0
today! Here are some feature highlights ๐:
Transactionโ
[#222] Use database transaction to perform atomic operations
Two transaction APIs are provided:
closure
style. Will be committed on Ok and rollback on Err.// <Fn, A, B> -> Result<A, B>
db.transaction::<_, _, DbErr>(|txn| {
Box::pin(async move {
bakery::ActiveModel {
name: Set("SeaSide Bakery".to_owned()),
..Default::default()
}
.save(txn)
.await?;
bakery::ActiveModel {
name: Set("Top Bakery".to_owned()),
..Default::default()
}
.save(txn)
.await?;
Ok(())
})
})
.await;RAII style.
begin
the transaction followed bycommit
orrollback
. Iftxn
goes out of scope, it'd automatically rollback.let txn = db.begin().await?;
// do something with txn
txn.commit().await?;
Contributed by:
Streamingโ
[#222] Use async stream on any Select
for memory efficiency.
let mut stream = Fruit::find().stream(&db).await?;
while let Some(item) = stream.try_next().await? {
let item: fruit::ActiveModel = item.into();
// do something with item
}
Contributed by:
API for custom logic on save & deleteโ
[#210] We redefined the trait methods of ActiveModelBehavior
. You can now perform custom validation before and after insert
, update
, save
, delete
actions. You can abort an action even after it is done, if you are inside a transaction.
impl ActiveModelBehavior for ActiveModel {
// Override default values
fn new() -> Self {
Self {
serial: Set(Uuid::new_v4()),
..ActiveModelTrait::default()
}
}
// Triggered before insert / update
fn before_save(self, insert: bool) -> Result<Self, DbErr> {
if self.price.as_ref() <= &0.0 {
Err(DbErr::Custom(format!(
"[before_save] Invalid Price, insert: {}",
insert
)))
} else {
Ok(self)
}
}
// Triggered after insert / update
fn after_save(self, insert: bool) -> Result<Self, DbErr> {
Ok(self)
}
// Triggered before delete
fn before_delete(self) -> Result<Self, DbErr> {
Ok(self)
}
// Triggered after delete
fn after_delete(self) -> Result<Self, DbErr> {
Ok(self)
}
}
Contributed by:
Generate Entity Models That Derive Serialize / Deserializeโ
[#237] You can use sea-orm-cli
to generate entity models that also derive serde Serialize
/ Deserialize
traits.
//! SeaORM Entity. Generated by sea-orm-codegen 0.3.0
use sea_orm::entity::prelude:: * ;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
}
// ...
Contributed by:
Introduce DeriveIntoActiveModel
macro & IntoActiveValue
Traitโ
[#240] introduced a new derive macro DeriveIntoActiveModel
for implementing IntoActiveModel
on structs. This is useful when creating your own struct with only partial fields of a model, for example as a form submission in a REST API.
IntoActiveValue
trait allows converting Option<T>
into ActiveValue<T>
with the method into_active_value
.
// Define regular model as usual
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
#[sea_orm(table_name = "users")]
pub struct Model {
pub id: Uuid,
pub created_at: DateTimeWithTimeZone,
pub updated_at: DateTimeWithTimeZone,
pub email: String,
pub password: String,
pub full_name: Option<String>,
pub phone: Option<String>,
}
// Create a new struct with some fields omitted
#[derive(DeriveIntoActiveModel)]
pub struct NewUser {
// id, created_at and updated_at are omitted from this struct,
// and will always be `ActiveValue::unset`
pub email: String,
pub password: String,
// Full name is usually optional, but it can be required here
pub full_name: String,
// Option implements `IntoActiveValue`, and when `None` will be `unset`
pub phone: Option<String>,
}
#[derive(DeriveIntoActiveModel)]
pub struct UpdateUser {
// Option<Option<T>> allows for Some(None) to update the column to be NULL
pub phone: Option<Option<String>>,
}
Contributed by:
Communityโ
SeaQL is a community driven project. We welcome you to participate, contribute and together build for Rust's future.
Here is the roadmap for SeaORM 0.4.x
.