Releases: SeaQL/sea-orm
Releases Β· SeaQL/sea-orm
0.12.1
New Features
- Added
MigratorTrait::migration_table_name()
method to configure the name of migration table #1511
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
// Override the name of migration table
fn migration_table_name() -> sea_orm::DynIden {
Alias::new("override_migration_table_name").into_iden()
}
...
}
- Added option to construct chained AND / OR join on condition #1433
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
// By default, it's
// `JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` AND `fruit`.`name` LIKE '%tropical%'`
#[sea_orm(
has_many = "super::fruit::Entity",
on_condition = r#"super::fruit::Column::Name.like("%tropical%")"#
)]
TropicalFruit,
// Or specify `condition_type = "any"` to override it,
// `JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` OR `fruit`.`name` LIKE '%tropical%'`
#[sea_orm(
has_many = "super::fruit::Entity",
on_condition = r#"super::fruit::Column::Name.like("%tropical%")"#
condition_type = "any",
)]
OrTropicalFruit,
}
- Supports entity with composite primary key of arity 12 #1508
Identity
supports tuple ofDynIden
with arity up to 12
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "primary_key_of_12")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id_1: String,
...
#[sea_orm(primary_key, auto_increment = false)]
pub id_12: bool,
}
- Added macro
DerivePartialModel
#1597
#[derive(DerivePartialModel, FromQueryResult)]
#[sea_orm(entity = "Cake")]
struct PartialCake {
name: String,
#[sea_orm(
from_expr = r#"SimpleExpr::FunctionCall(Func::upper(Expr::col((Cake, cake::Column::Name))))"#
)]
name_upper: String,
}
assert_eq!(
cake::Entity::find()
.into_partial_model::<PartialCake>()
.into_statement(DbBackend::Sqlite)
.to_string(),
r#"SELECT "cake"."name", UPPER("cake"."name") AS "name_upper" FROM "cake""#
);
- Added
DbErr::sql_err()
method to convert error into common database errorsSqlErr
, such as unique constraint or foreign key violation errors. #1707
assert!(matches!(
cake.into_active_model().insert(db).await
.expect_err("Insert a row with duplicated primary key")
.sql_err(),
Some(SqlErr::UniqueConstraintViolation(_))
));
assert!(matches!(
fk_cake.insert(db).await
.expect_err("Insert a row with invalid foreign key")
.sql_err(),
Some(SqlErr::ForeignKeyConstraintViolation(_))
));
fn find_with_related<R>(self, r: R) -> SelectTwoMany<E, R>
where R: EntityTrait, E: Related<R>;
fn find_with_linked<L, T>(self, l: L) -> SelectTwoMany<E, T>
where L: Linked<FromEntity = E, ToEntity = T>, T: EntityTrait;
// boths yields `Vec<(E::Model, Vec<F::Model>)>`
- Added
DeriveValueType
derive macro for custom wrapper types, implementations of the required traits will be provided, you can customize thecolumn_type
andarray_type
if needed #1720
#[derive(DeriveValueType)]
#[sea_orm(array_type = "Int")]
pub struct Integer(i32);
#[derive(DeriveValueType)]
#[sea_orm(column_type = "Boolean", array_type = "Bool")]
pub struct Boolbean(pub String);
#[derive(DeriveValueType)]
pub struct StringVec(pub Vec<String>);
- Added
DeriveDisplay
derive macro to implementsstd::fmt::Display
for enum #1726
#[derive(DeriveDisplay)]
enum DisplayTea {
EverydayTea,
#[sea_orm(display_value = "Breakfast Tea")]
BreakfastTea,
}
assert_eq!(format!("{}", DisplayTea::EverydayTea), "EverydayTea");
assert_eq!(format!("{}", DisplayTea::BreakfastTea), "Breakfast Tea");
- Added
UpdateMany::exec_with_returning()
#1677
let models: Vec<Model> = Entity::update_many()
.col_expr(Column::Values, Expr::expr(..))
.exec_with_returning(db)
.await?;
- Supporting
default_expr
inDeriveEntityModel
#1474
#[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())
);
- Introduced new
ConnAcquireErr
#1737
enum DbErr {
ConnectionAcquire(ConnAcquireErr),
..
}
enum ConnAcquireErr {
Timeout,
ConnectionClosed,
}
Seaography
Added Seaography integration #1599
-
Added
DeriveEntityRelated
macro which will implementseaography::RelationBuilder
forRelatedEntity
enumeration when theseaography
feature is enabled -
Added generation of
seaography
related information tosea-orm-codegen
.The
RelatedEntity
enum is added in entities files bysea-orm-cli
when flagseaography
is set:
/// SeaORM Entity
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(entity = "super::bakery::Entity")]
Bakery,
#[sea_orm(entity = "super::cake_baker::Entity")]
CakeBaker,
#[sea_orm(entity = "super::cake::Entity")]
Cake,
}
- Added
seaography_example
Enhancements
- Supports for partial select of
Option<T>
model field. ANone
value will be filled when the select result does not contain theOption<T>
field without throwing an error. #1513 - [sea-orm-cli] the
migrate init
command will create a.gitignore
file when the migration folder reside in a Git repository #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 createm20230503_000000_create_accounts_table.rs
for you #1570 - Added
Migration::name()
andMigration::status()
getters for the name and status ofsea_orm_migration::Migration
#1519
let migrations = Migrator::get_pending_migrations(db).await?;
assert_eq!(migrations.len(), 5);
let migration = migrations.get(0).unwrap();
assert_eq!(migration.name(), "m20220118_000002_create_fruit_table");
assert_eq!(migration.status(), MigrationStatus::Pending);
- The
postgres-array
feature will be enabled whensqlx-postgres
backend is selected #1565 - Replace
String
parameters in API withInto<String>
#1439- Implements
IntoMockRow
for anyBTreeMap
that is indexed by stringimpl IntoMockRow for BTreeMap<T, Value> where T: Into<String>
- Converts any string value into
ConnectOptions
-impl From<T> for ConnectOptions where T: Into<String>
- Changed the parameter of method
ConnectOptions::new(T) where T: Into<String>
to takes any string SQL - Changed the parameter of method
Statement::from_string(DbBackend, T) where T: Into<String>
to takes any string SQL - Changed the parameter of method
Statement::from_sql_and_values(DbBackend, T, I) where I: IntoIterator<Item = Value>, T: Into<String>
to takes any string SQL - Changed the parameter of method
Transaction::from_sql_and_values(DbBackend, T, I) where I: IntoIterator<Item = Value>, T: Into<String>
to takes any string SQL - Changed the parameter of method
ConnectOptions::set_schema_search_path(T) where T: Into<String>
to takes any string - Changed the parameter of method
ColumnTrait::like()
,ColumnTrait::not_like()
,ColumnTrait::starts_with()
,ColumnTrait::ends_with()
andColumnTrait::contains()
to takes any string
- Implements
- Added
sea_query::{DynIden, RcOrArc, SeaRc}
to entity prelude #1661 - Added
expr
,exprs
andexpr_as
methods toQuerySelect
trait #1702 - Added
DatabaseConnection::ping
#1627
|db: DatabaseConnection| {
assert!(db.ping().await.is_ok());
db.clone().close().await;
assert!(matches!(db.ping().await, Err(DbErr::ConnectionAcquire)));
}
- Added
TryInsert
that does not panic on empty inserts #1708
// now, you can do:
let res = Bakery::insert_many(std::iter::empty())
.on_empty_do_nothing()
.exec(db)
.await;
assert!(matches!(res, Ok(TryInsertResult::Empty)));
- Insert on conflict do nothing to return Ok #1712
let on = OnConflict::column(Column::Id).do_nothing().to_owned();
// Existing behaviour
let res = Entity::insert_many([..]).on_conflict(on).exec(db).await;
assert!(matches!(res, Err(DbErr::RecordNotInserted)));
// New API; now you can:
let res =
Entity::insert_many([..]).on_conflict(on).do_nothing().exec(db).await;
assert!(matche...
0.11.3
Enhancements
- Re-export
sea_orm::ConnectionTrait
insea_orm_migration::prelude
#1577 - Support generic structs in
FromQueryResult
derive macro #1464, #1603
#[derive(FromQueryResult)]
struct GenericTest<T: TryGetable> {
foo: i32,
bar: T,
}
trait MyTrait {
type Item: TryGetable;
}
#[derive(FromQueryResult)]
struct TraitAssociateTypeTest<T>
where
T: MyTrait,
{
foo: T::Item,
}
Bug Fixes
0.11.2
0.11.1
Bug Fixes
- Fixes
DeriveActiveEnum
(by qualifyingColumnTypeTrait::def
) #1478 - The CLI command
sea-orm-cli generate entity -u '<DB-URL>'
will now generate the following code for eachBinary
orVarBinary
columns in compact format #1529
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "binary")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(column_type = "Binary(BlobSize::Blob(None))")]
pub binary: Vec<u8>,
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(10)))")]
pub binary_10: Vec<u8>,
#[sea_orm(column_type = "Binary(BlobSize::Tiny)")]
pub binary_tiny: Vec<u8>,
#[sea_orm(column_type = "Binary(BlobSize::Medium)")]
pub binary_medium: Vec<u8>,
#[sea_orm(column_type = "Binary(BlobSize::Long)")]
pub binary_long: Vec<u8>,
#[sea_orm(column_type = "VarBinary(10)")]
pub var_binary: Vec<u8>,
}
- The CLI command
sea-orm-cli generate entity -u '<DB-URL>' --expanded-format
will now generate the following code for eachBinary
orVarBinary
columns in expanded format #1529
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Integer.def(),
Self::Binary => ColumnType::Binary(sea_orm::sea_query::BlobSize::Blob(None)).def(),
Self::Binary10 => {
ColumnType::Binary(sea_orm::sea_query::BlobSize::Blob(Some(10u32))).def()
}
Self::BinaryTiny => ColumnType::Binary(sea_orm::sea_query::BlobSize::Tiny).def(),
Self::BinaryMedium => ColumnType::Binary(sea_orm::sea_query::BlobSize::Medium).def(),
Self::BinaryLong => ColumnType::Binary(sea_orm::sea_query::BlobSize::Long).def(),
Self::VarBinary => ColumnType::VarBinary(10u32).def(),
}
}
}
Full Changelog: 0.11.0...0.11.1
0.11.0
https://www.sea-ql.org/blog/2023-02-08-whats-new-in-seaorm-0.11.0/
New Features
SeaORM Core
- Simple data loader #1238, #1443
- Transactions Isolation level and Access mode #1230
- Support various UUID formats that are available in
uuid::fmt
module #1325 - Support Vector of enum for Postgres #1210
- Support
ActiveEnum
field as primary key #1414 - Casting columns as a different data type on select, insert and update #1304
- Methods of
ActiveModelBehavior
receive db connection as a parameter #1145, #1328 - Added
execute_unprepared
method toDatabaseConnection
andDatabaseTransaction
#1327 - Added
Select::into_tuple
to select rows as tuples (instead of defining a custom Model) #1311
SeaORM CLI
- Generate
#[serde(skip_deserializing)]
for primary key columns #846, #1186, #1318 - Generate
#[serde(skip)]
for hidden columns #1171, #1320 - Generate entity with extra derives and attributes for model struct #1124, #1321
SeaORM Migration
- Migrations are now performed inside a transaction for Postgres #1379
Enhancements
- Refactor schema module to expose functions for database alteration #1256
- Generate compact entity with
#[sea_orm(column_type = "JsonBinary")]
macro attribute #1346 MockDatabase::append_exec_results()
,MockDatabase::append_query_results()
,MockDatabase::append_exec_errors()
andMockDatabase::append_query_errors()
take any types implementedIntoIterator
trait #1367find_by_id
anddelete_by_id
take anyInto
primary key value #1362QuerySelect::offset
andQuerySelect::limit
takes inInto<Option<u64>>
whereNone
would reset them #1410- Added
DatabaseConnection::close
#1236 - Added
is_null
getter forColumnDef
#1381 - Added
ActiveValue::reset
to convertUnchanged
intoSet
#1177 - Added
QueryTrait::apply_if
to optionally apply a filter #1415 - Added the
sea-orm-internal
feature flag to expose some SQLx types
Upgrades
- Upgrade
axum
to0.6.1
#1285 - Upgrade
sea-query
to0.28
#1366 - Upgrade
sea-query-binder
to0.3
#1366 - Upgrade
sea-schema
to0.11
#1366
House Keeping
- Fixed all clippy warnings as of
1.67.0
#1426 - Removed dependency where not needed #1213
- Disabled default features and enabled only the needed ones #1300
- Cleanup panic and unwrap #1231
- Cleanup the use of
vec!
macro #1367
Bug Fixes
- [sea-orm-cli] Propagate error on the spawned child processes #1402
- Fixes sea-orm-cli errors exit with error code 0 #1342
- Fixes
DeriveColumn
(by qualifyingIdenStatic::as_str
) #1280 - Prevent returning connections to pool with a positive transaction depth #1283
- Postgres insert many will throw
RecordNotInserted
error if non of them are being inserted #1021- Fixes inserting active models by
insert_many
withon_conflict
anddo_nothing
panics if no rows are inserted on Postgres #899
- Fixes inserting active models by
- Don't call
last_insert_id
if not needed #1403- Fixes hitting 'negative last_insert_rowid' panic with Sqlite #1357
- Noop when update without providing any values #1384
- Fixes Syntax Error when saving active model that sets nothing #1376
Breaking changes
- [sea-orm-cli] Enable --universal-time by default #1420
- Added
RecordNotInserted
andRecordNotUpdated
toDbErr
- Added
ConnectionTrait::execute_unprepared
method #1327 - As part of #1311, the required method of
TryGetable
changed:
// then
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError>;
// now; ColIdx can be `&str` or `usize`
fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError>;
So if you implemented it yourself:
impl TryGetable for XXX {
- fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
+ fn try_get_by<I: sea_orm::ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
- let value: YYY = res.try_get(pre, col).map_err(TryGetError::DbErr)?;
+ let value: YYY = res.try_get_by(idx).map_err(TryGetError::DbErr)?;
..
}
}
- The
ActiveModelBehaviour
trait becomes async trait #1328.
If you overridden the defaultActiveModelBehaviour
implementation:
#[async_trait::async_trait]
impl ActiveModelBehavior for ActiveModel {
async fn before_save<C>(self, db: &C, insert: bool) -> Result<Self, DbErr>
where
C: ConnectionTrait,
{
// ...
}
// ...
}
DbErr::RecordNotFound("None of the database rows are affected")
is moved to a dedicated error variantDbErr::RecordNotUpdated
#1425
let res = Update::one(cake::ActiveModel {
name: Set("Cheese Cake".to_owned()),
..model.into_active_model()
})
.exec(&db)
.await;
// then
assert_eq!(
res,
Err(DbErr::RecordNotFound(
"None of the database rows are affected".to_owned()
))
);
// now
assert_eq!(res, Err(DbErr::RecordNotUpdated));
sea_orm::ColumnType
was replaced bysea_query::ColumnType
#1395- Method
ColumnType::def
was moved toColumnTypeTrait
ColumnType::Binary
becomes a tuple variant which takes in additional optionsea_query::BlobSize
ColumnType::Custom
takes asea_query::DynIden
instead ofString
and thus a new methodcustom
is added (note the lowercase)
- Method
// Compact Entity
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "fruit")]
pub struct Model {
- #[sea_orm(column_type = r#"Custom("citext".to_owned())"#)]
+ #[sea_orm(column_type = r#"custom("citext")"#)]
pub column: String,
}
// Expanded Entity
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
- Self::Column => ColumnType::Custom("citext".to_owned()).def(),
+ Self::Column => ColumnType::custom("citext").def(),
}
}
}
Miscellaneous
New Contributors
- @goto-eof made their first contribution in #1234
- @tdejager made their first contribution in #1240
- @limjiayi made their first contribution in #1260
- @hut8 made their first contribution in #1302
- @as-cii made their first contribution in #1283
- @karatakis made their first contribution in #1238
- @LeoniePhiline made their first contribution in #1391
- @daniel-samson made their first contribution in #1405
- @Diwakar-Gupta made their first contribution in #1402
- @cemremengu made their first contribution in #1428
- @ippsav made their first contribution in #1430
Full Changelog: 0.10.0...0.11.0
0.11.0-rc.2
See 0.11.0 release notes
0.11.0-rc.1
See 0.11.0 release notes
0.10.7
0.10.6
Enhancements
- Cast enum values when constructing update many query #1178
Bug Fixes
- Fixes
DeriveColumn
(by qualifyingIdenStatic::as_str
) #1280 - Prevent returning connections to pool with a positive transaction depth #1283
- [sea-orm-codegen] Skip implementing Related if the same related entity is being referenced by a conjunct relation #1298
- [sea-orm-cli] CLI depends on codegen of the same version #1299
Full Changelog: 0.10.5...0.10.6
0.10.5
New Features
- Add
QuerySelect::columns
method - select multiple columns #1264 - Transactions Isolation level and Access mode #1230
Bug Fixes
DeriveEntityModel
derive macro: when parsing field type, always treat field withOption<T>
as nullable column #1257
Enhancements
- [sea-orm-cli] Generate
Related
implementation for many-to-many relation with extra columns #1260 - Optimize the default implementation of
TryGetableFromJson::try_get_from_json()
- deserializing intoSelf
directly without the need of a intermediateserde_json::Value
#1249
Full Changelog: 0.10.4...0.10.5