π We are pleased to release SeaORM 0.9.0
today! Here are some feature highlights π:
Dependency Upgradesβ
[#834] We have upgraded a few major dependencies:
- Upgrade
sqlx
to 0.6 - Upgrade
time
to 0.3 - Upgrade
uuid
to 1.0 - Upgrade
sea-query
to 0.26 - Upgrade
sea-schema
to 0.9
Note that you might need to upgrade the corresponding dependency on your application as well.
Cursor Paginationβ
[#822] Paginate models based on column(s) such as the primary key.
// Create a cursor that order by `cake`.`id`
let mut cursor = cake::Entity::find().cursor_by(cake::Column::Id);
// Filter paginated result by `cake`.`id` > 1 AND `cake`.`id` < 100
cursor.after(1).before(100);
// Get first 10 rows (order by `cake`.`id` ASC)
let rows: Vec<cake::Model> = cursor.first(10).all(db).await?;
// Get last 10 rows (order by `cake`.`id` DESC but rows are returned in ascending order)
let rows: Vec<cake::Model> = cursor.last(10).all(db).await?;
Insert On Conflictβ
[#791] Insert an active model with on conflict behaviour.
let orange = cake::ActiveModel {
id: ActiveValue::set(2),
name: ActiveValue::set("Orange".to_owned()),
};
// On conflict do nothing:
// - INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO NOTHING
cake::Entity::insert(orange.clone())
.on_conflict(
sea_query::OnConflict::column(cake::Column::Name)
.do_nothing()
.to_owned()
)
.exec(db)
.await?;
// On conflict do update:
// - INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO UPDATE SET "name" = "excluded"."name"
cake::Entity::insert(orange)
.on_conflict(
sea_query::OnConflict::column(cake::Column::Name)
.update_column(cake::Column::Name)
.to_owned()
)
.exec(db)
.await?;
Join Table with Custom Conditions and Table Aliasβ
[#793, #852] Click Custom Join Conditions and Custom Joins to learn more.
assert_eq!(
cake::Entity::find()
.column_as(
Expr::tbl(Alias::new("fruit_alias"), fruit::Column::Name).into_simple_expr(),
"fruit_name"
)
.join_as(
JoinType::LeftJoin,
cake::Relation::Fruit
.def()
.on_condition(|_left, right| {
Expr::tbl(right, fruit::Column::Name)
.like("%tropical%")
.into_condition()
}),
Alias::new("fruit_alias")
)
.build(DbBackend::MySql)
.to_string(),
[
"SELECT `cake`.`id`, `cake`.`name`, `fruit_alias`.`name` AS `fruit_name` FROM `cake`",
"LEFT JOIN `fruit` AS `fruit_alias` ON `cake`.`id` = `fruit_alias`.`cake_id` AND `fruit_alias`.`name` LIKE '%tropical%'",
]
.join(" ")
);
(de)serialize Custom JSON Typeβ
[#794] JSON stored in the database could be deserialized into custom struct in Rust.
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "json_struct")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
// JSON column defined in `serde_json::Value`
pub json: Json,
// JSON column defined in custom struct
pub json_value: KeyValue,
pub json_value_opt: Option<KeyValue>,
}
// The custom struct must derive `FromJsonQueryResult`, `Serialize` and `Deserialize`
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, FromJsonQueryResult)]
pub struct KeyValue {
pub id: i32,
pub name: String,
pub price: f32,
pub notes: Option<String>,
}
Derived Migration Nameβ
[#736] Introduce DeriveMigrationName
procedural macros to infer migration name from the file name.
use sea_orm_migration::prelude::*;
// Used to be...
pub struct Migration;
impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220120_000001_create_post_table"
}
}
// Now... derive `DeriveMigrationName`,
// no longer have to specify the migration name explicitly
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table( ... )
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table( ... )
.await
}
}
SeaORM CLI Improvementsβ
- [#735] Improve logging of generate entity command
- [#588] Generate enum with numeric like variants
- [#755] Allow old pending migration to be applied
- [#837] Skip generating entity for ignored tables
- [#724] Generate code for
time
crate - [#850] Add various blob column types
- [#422] Generate entity files with Postgres's schema name
- [#851] Skip checking connection string for credentials
Miscellaneous Enhancementsβ
- [#800] Added
sqlx_logging_level
toConnectOptions
- [#768] Added
num_items_and_pages
toPaginator
- [#849] Added
TryFromU64
fortime
- [#853] Include column name in
TryGetError::Null
- [#778] Refactor stream metrics
Integration Examplesβ
SeaORM plays well with the other crates in the async ecosystem. We maintain an array of example projects for building REST, GraphQL and gRPC services. More examples wanted!
- Actix v4 Example
- Axum Example
- GraphQL Example
- jsonrpsee Example
- Poem Example
- Rocket Example
- Salvo Example
- Tonic Example
Sponsorβ
Our GitHub Sponsor profile is up! If you feel generous, a small donation will be greatly appreciated.
A big shout out to our sponsors π:
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.10.x
.