๐ 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.
Proposed by:
Contributed by:
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?;
Proposed by:
Contributed by:
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?;
Proposed by:
Contributed by:
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(" ")
);
Proposed by:
Contributed by:
(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 much 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>,
}
Proposed by:
Contributed by:
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
}
}
Proposed by:
Contributed by:
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
Proposed & Contributed by:
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
Proposed & Contributed by:
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!
- Rocket Example
- Actix Example
- Axum Example
- Poem Example
- GraphQL Example
- jsonrpsee 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 ๐:
- รmile Fugulin
- Dean Sheather
- Shane Sveller
- Sakti Dwi Cahyono
- Unnamed Sponsor
- Unnamed Sponsor
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
.
Top comments (0)