Changelog

This commit is contained in:
Chris Tsang 2023-07-13 15:43:23 +01:00
parent 3629b91d01
commit 7352008e0e

View File

@ -14,45 +14,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### New Features ### New Features
* Supports for partial select of `Option<T>` model field. A `None` value will be filled when the select result does not contain the `Option<T>` field without throwing an error. https://github.com/SeaQL/sea-orm/pull/1513
```rust
customer::ActiveModel {
name: Set("Alice".to_owned()),
notes: Set(Some("Want to communicate with Bob".to_owned())),
..Default::default()
}
.save(db)
.await?;
// The `notes` field was intentionally leaved out
let customer = Customer::find()
.select_only()
.column(customer::Column::Id)
.column(customer::Column::Name)
.one(db)
.await
.unwrap();
// The select result does not contain `notes` field.
// Since it's of type `Option<String>`, it'll be `None` and no error will be thrown.
assert_eq!(customers.notes, None);
```
* [sea-orm-cli] the `migrate init` command will create a `.gitignore` file when the migration folder reside in a Git repository https://github.com/SeaQL/sea-orm/pull/1334
* Added `MigratorTrait::migration_table_name()` method to configure the name of migration table https://github.com/SeaQL/sea-orm/pull/1511 * Added `MigratorTrait::migration_table_name()` method to configure the name of migration table https://github.com/SeaQL/sea-orm/pull/1511
```rust ```rust
#[async_trait::async_trait] #[async_trait::async_trait]
impl MigratorTrait for Migrator { impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220118_000001_create_cake_table::Migration),
Box::new(m20220118_000002_create_fruit_table::Migration),
]
}
// Override the name of migration table // Override the name of migration table
fn migration_table_name() -> sea_orm::DynIden { fn migration_table_name() -> sea_orm::DynIden {
Alias::new("override_migration_table_name").into_iden() Alias::new("override_migration_table_name").into_iden()
} }
...
} }
``` ```
* Added option to construct chained AND / OR join on condition https://github.com/SeaQL/sea-orm/pull/1433 * Added option to construct chained AND / OR join on condition https://github.com/SeaQL/sea-orm/pull/1433
@ -64,7 +34,6 @@ use sea_orm::entity::prelude::*;
pub struct Model { pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: i32, pub id: i32,
#[sea_orm(column_name = "name", enum_name = "Name")]
pub name: String, pub name: String,
} }
@ -86,40 +55,6 @@ pub enum Relation {
)] )]
OrTropicalFruit, OrTropicalFruit,
} }
impl ActiveModelBehavior for ActiveModel {}
```
You can also override it in custom join.
```rust
assert_eq!(
cake::Entity::find()
.column_as(
Expr::col((Alias::new("cake_filling_alias"), cake_filling::Column::CakeId)),
"cake_filling_cake_id"
)
.join(JoinType::LeftJoin, cake::Relation::OrTropicalFruit.def())
.join_as_rev(
JoinType::LeftJoin,
cake_filling::Relation::Cake
.def()
// chained AND / OR join on condition
.condition_type(ConditionType::Any)
.on_condition(|left, _right| {
Expr::col((left, cake_filling::Column::CakeId))
.gt(10)
.into_condition()
}),
Alias::new("cake_filling_alias")
)
.build(DbBackend::MySql)
.to_string(),
[
"SELECT `cake`.`id`, `cake`.`name`, `cake_filling_alias`.`cake_id` AS `cake_filling_cake_id` FROM `cake`",
"LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` OR `fruit`.`name` LIKE '%tropical%'",
"LEFT JOIN `cake_filling` AS `cake_filling_alias` ON `cake_filling_alias`.`cake_id` = `cake`.`id` OR `cake_filling_alias`.`cake_id` > 10",
]
.join(" ")
);
``` ```
* Supports entity with composite primary key of length 12 https://github.com/SeaQL/sea-orm/pull/1508 * Supports entity with composite primary key of length 12 https://github.com/SeaQL/sea-orm/pull/1508
* Implemented `IntoIdentity` for `Identity` https://github.com/SeaQL/sea-orm/pull/1508 * Implemented `IntoIdentity` for `Identity` https://github.com/SeaQL/sea-orm/pull/1508
@ -136,37 +71,10 @@ use sea_orm::entity::prelude::*;
pub struct Model { pub struct Model {
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id_1: String, pub id_1: String,
#[sea_orm(primary_key, auto_increment = false)] ...
pub id_2: i8,
#[sea_orm(primary_key, auto_increment = false)]
pub id_3: u8,
#[sea_orm(primary_key, auto_increment = false)]
pub id_4: i16,
#[sea_orm(primary_key, auto_increment = false)]
pub id_5: u16,
#[sea_orm(primary_key, auto_increment = false)]
pub id_6: i32,
#[sea_orm(primary_key, auto_increment = false)]
pub id_7: u32,
#[sea_orm(primary_key, auto_increment = false)]
pub id_8: i64,
#[sea_orm(primary_key, auto_increment = false)]
pub id_9: u64,
#[sea_orm(primary_key, auto_increment = false)]
pub id_10: f32,
#[sea_orm(primary_key, auto_increment = false)]
pub id_11: f64,
#[sea_orm(primary_key, auto_increment = false)] #[sea_orm(primary_key, auto_increment = false)]
pub id_12: bool, pub id_12: bool,
pub owner: String,
pub name: String,
pub description: String,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
``` ```
* Added macro `DerivePartialModel` https://github.com/SeaQL/sea-orm/pull/1597 * Added macro `DerivePartialModel` https://github.com/SeaQL/sea-orm/pull/1597
```rust ```rust
@ -188,31 +96,6 @@ assert_eq!(
r#"SELECT "cake"."name", UPPER("cake"."name") AS "name_upper" FROM "cake""# r#"SELECT "cake"."name", UPPER("cake"."name") AS "name_upper" FROM "cake""#
); );
``` ```
* [sea-orm-cli] Added support for generating migration of space separated name, for example executing `sea-orm-cli migrate generate "create accounts table"` command will create `m20230503_000000_create_accounts_table.rs` for you https://github.com/SeaQL/sea-orm/pull/1570
* Add `seaography` flag to `sea-orm`, `sea-orm-orm-macros` and `sea-orm-cli` https://github.com/SeaQL/sea-orm/pull/1599
* Add generation of `seaography` related information to `sea-orm-codegen` https://github.com/SeaQL/sea-orm/pull/1599
The following information is added in entities files by `sea-orm-cli` when flag `seaography` is `true`
```rust
/// ... Entity File ...
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::address::Entity")]
Address,
#[sea_orm(entity = "super::payment::Entity")]
Payment,
#[sea_orm(entity = "super::rental::Entity")]
Rental,
#[sea_orm(entity = "Entity", def = "Relation::SelfRef.def()")]
SelfRef,
#[sea_orm(entity = "super::store::Entity")]
Store,
#[sea_orm(entity = "Entity", def = "Relation::SelfRef.def().rev()")]
SelfRefRev,
}
```
* Add `DeriveEntityRelated` macro https://github.com/SeaQL/sea-orm/pull/1599 * Add `DeriveEntityRelated` macro https://github.com/SeaQL/sea-orm/pull/1599
The DeriveRelatedEntity derive macro will implement `seaography::RelationBuilder` for `RelatedEntity` enumeration when the `seaography` feature is enabled The DeriveRelatedEntity derive macro will implement `seaography::RelationBuilder` for `RelatedEntity` enumeration when the `seaography` feature is enabled
@ -297,91 +180,91 @@ pub struct Boolbean(pub String);
#[derive(DeriveValueType)] #[derive(DeriveValueType)]
pub struct StringVec(pub Vec<String>); pub struct StringVec(pub Vec<String>);
``` ```
The expanded code of `DeriveValueType` looks like.
```rust
#[derive(DeriveValueType)]
pub struct StringVec(pub Vec<String>);
// The `DeriveValueType` will be expanded into...
impl From<StringVec> for Value {
fn from(source: StringVec) -> Self {
source.0.into()
}
}
impl sea_orm::TryGetable for StringVec {
fn try_get_by<I: sea_orm::ColIdx>(res: &QueryResult, idx: I) -> Result<Self, sea_orm::TryGetError> {
<Vec<String> as sea_orm::TryGetable>::try_get_by(res, idx).map(|v| StringVec(v))
}
}
impl sea_orm::sea_query::ValueType for StringVec {
fn try_from(v: Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> {
<Vec<String> as sea_orm::sea_query::ValueType>::try_from(v).map(|v| StringVec(v))
}
fn type_name() -> String {
stringify!(StringVec).to_owned()
}
fn array_type() -> sea_orm::sea_query::ArrayType {
std::convert::Into::<sea_orm::sea_query::ArrayType>::into(
<Vec<String> as sea_orm::sea_query::ValueType>::array_type()
)
}
fn column_type() -> sea_orm::sea_query::ColumnType {
std::convert::Into::<sea_orm::sea_query::ColumnType>::into(
<Vec<String> as sea_orm::sea_query::ValueType>::column_type()
)
}
}
```
* Add `DeriveDisplay` derive macro to implements `std::fmt::Display` for active enum https://github.com/SeaQL/sea-orm/pull/1726 * Add `DeriveDisplay` derive macro to implements `std::fmt::Display` for active enum https://github.com/SeaQL/sea-orm/pull/1726
```rust ```rust
// String enum #[derive(DeriveDisplay)]
#[derive(EnumIter, DeriveActiveEnum, DeriveDisplay)]
#[sea_orm(rs_type = "String", db_type = "String(Some(1))", enum_name = "category")]
pub enum DeriveCategory {
#[sea_orm(string_value = "B")]
Big,
#[sea_orm(string_value = "S")]
Small,
}
assert_eq!(format!("{}", DeriveCategory::Big), "Big");
assert_eq!(format!("{}", DeriveCategory::Small), "Small");
// Numeric enum
#[derive(EnumIter, DeriveActiveEnum, DeriveDisplay)]
#[sea_orm(rs_type = "i32", db_type = "Integer")]
pub enum $ident {
#[sea_orm(num_value = -10)]
Negative,
#[sea_orm(num_value = 1)]
Big,
#[sea_orm(num_value = 0)]
Small,
}
assert_eq!(format!("{}", $ident::Big), "Big");
assert_eq!(format!("{}", $ident::Small), "Small");
assert_eq!(format!("{}", $ident::Negative), "Negative");
// String enum with `display_value` overrides
#[derive(EnumIter, DeriveActiveEnum, DeriveDisplay)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")]
pub enum DisplayTea { pub enum DisplayTea {
#[sea_orm(string_value = "EverydayTea", display_value = "Everyday")]
EverydayTea, EverydayTea,
#[sea_orm(string_value = "BreakfastTea", display_value = "Breakfast")] #[sea_orm(display_value = "Breakfast")]
BreakfastTea, BreakfastTea,
} }
assert_eq!(format!("{}", DisplayTea::EverydayTea), "EverydayTea");
assert_eq!(format!("{}", DisplayTea::BreakfastTea), "Breakfast"); assert_eq!(format!("{}", DisplayTea::BreakfastTea), "Breakfast");
assert_eq!(format!("{}", DisplayTea::EverydayTea), "Everyday"); ```
* Added `UpdateMany::exec_with_returning()` https://github.com/SeaQL/sea-orm/pull/1677
```rust
Entity::update_many()
.col_expr(Column::Values, Expr::expr(..))
.exec_with_returning(db)
.await
```
* Supporting `default_expr` in `DeriveEntityModel` https://github.com/SeaQL/sea-orm/pull/1474
```rust
#[derive(DeriveEntityModel)]
#[sea_orm(table_name = "hello")]
pub struct Model {
#[sea_orm(default_expr = "Expr::current_timestamp()")]
pub timestamp: DateTimeUtc,
}
assert_eq!(
Column::Timestamp.def(),
ColumnType::TimestampWithTimeZone.def().default(Expr::current_timestamp())
);
```
#### Seaography
* Add generation of `seaography` related information to `sea-orm-codegen` https://github.com/SeaQL/sea-orm/pull/1599
The following information is added in entities files by `sea-orm-cli` when flag `seaography` is `true`
```rust
/// ... Entity File ...
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::address::Entity")]
Address,
#[sea_orm(entity = "super::payment::Entity")]
Payment,
#[sea_orm(entity = "super::rental::Entity")]
Rental,
#[sea_orm(entity = "Entity", def = "Relation::SelfRef.def()")]
SelfRef,
#[sea_orm(entity = "super::store::Entity")]
Store,
#[sea_orm(entity = "Entity", def = "Relation::SelfRef.def().rev()")]
SelfRefRev,
}
``` ```
### Enhancements ### Enhancements
* Supports for partial select of `Option<T>` model field. A `None` value will be filled when the select result does not contain the `Option<T>` field without throwing an error. https://github.com/SeaQL/sea-orm/pull/1513
```rust
customer::ActiveModel {
name: Set("Alice".to_owned()),
notes: Set(Some("Want to communicate with Bob".to_owned())),
..Default::default()
}
.save(db)
.await?;
// The `notes` field was intentionally leaved out
let customer = Customer::find()
.select_only()
.column(customer::Column::Id)
.column(customer::Column::Name)
.one(db)
.await
.unwrap();
// The select result does not contain `notes` field.
// Since it's of type `Option<String>`, it'll be `None` and no error will be thrown.
assert_eq!(customers.notes, None);
```
* [sea-orm-cli] the `migrate init` command will create a `.gitignore` file when the migration folder reside in a Git repository https://github.com/SeaQL/sea-orm/pull/1334
* [sea-orm-cli] Added support for generating migration of space separated name, for example executing `sea-orm-cli migrate generate "create accounts table"` command will create `m20230503_000000_create_accounts_table.rs` for you https://github.com/SeaQL/sea-orm/pull/1570
* Added `Migration::name()` and `Migration::status()` getters for the name and status of `sea_orm_migration::Migration` https://github.com/SeaQL/sea-orm/pull/1519 * Added `Migration::name()` and `Migration::status()` getters for the name and status of `sea_orm_migration::Migration` https://github.com/SeaQL/sea-orm/pull/1519
```rust ```rust
let migrations = Migrator::get_pending_migrations(db).await?; let migrations = Migrator::get_pending_migrations(db).await?;
@ -432,13 +315,6 @@ assert!(matches!(res, Err(DbErr::RecordNotInserted)));
let res = Entity::insert_many([..]).on_conflict(on).do_nothing().exec(db).await; let res = Entity::insert_many([..]).on_conflict(on).do_nothing().exec(db).await;
assert!(matches!(res, Ok(TryInsertResult::Conflicted))); assert!(matches!(res, Ok(TryInsertResult::Conflicted)));
``` ```
* Added `UpdateMany::exec_with_returning()` https://github.com/SeaQL/sea-orm/pull/1677
```rust
Entity::update_many()
.col_expr(Column::Values, Expr::expr(..))
.exec_with_returning(db)
.await
```
### Upgrades ### Upgrades