sea-orm-migration
Migration utility for SeaORM
2.0.2
11M downloads/mo
#2925 most downloaded on crates.io
SeaQL/sea-orm
What this package is like to depend on
Last release 11 days ago
12 Aug 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 51 of 56 stable releases
3 versions withdrawn
withdrawn after publishing
4 years old
118 releases · first in 2022
47 releases in the last 12 months
see the full history below
Release timeline
118 releases · May 2022 to Aug 2026Releases
latest 60 of 118-
2.0.212 Aug 2026Release notes
Open source →SeaORM 2.0.2
Enhancements
- Add
require_oneto fetch exactly one row, erroring if none: a non-optional counterpart toone()that returns the item directly and yieldsDbErr::RecordNotFoundwhen no row matches, so call sites can use?instead of unwrapping anOption. Available onSelector/SelectorRawand theSelect,SelectTwo, andSelectTwoRequiredwrappers #3164 - Add
date_time_default_nowschema helper — a column defaulting toExpr::current_timestamp()#3159 - Add
timestamp_default_nowandtimestamp_with_time_zone_default_nowschema helpers, mirroringdate_time_default_nowfor the timestamp family #3165
Bug Fixes
- CLI: deduplicate grouped vs individual imports when regenerating entities with
--preserve-user-modifications, so a user-groupeduse foo::{A, B}is recognised as equivalent to the freshly generateduse foo::A; use foo::B;and no longer emitted twice #3163
Release notes
Open source →require_onequery helper,date_time_default_now/timestamp_default_nowschema helpers, entity-merge duplicate-import fix - Add
-
2.0.102 Aug 2026Release notes
Open source →SeaORM 2.0.1
Enhancements
- Add
set_pagetoPaginatorto set the current page #2963 - Add
as_option/into_optiontoActiveValue<Option<V>>, flattening the outer active-value state and the inner option #3155 - Add
set_unsetand friends toActiveValue: set the value only when currentlyNotSet#3083 - Add
is_set_and/is_unchanged_andtoActiveValue#3125 - Add
ConnectOptions::test_before_acquire_if_idle_for(Duration)— ping a pooled connection before it is handed out only once it has been idle for at least the given duration, instead of on every acquire; setting it disablestest_before_acquire. Alsomap_sqlx_postgres_before_acquire/map_sqlx_mysql_before_acquire/map_sqlx_sqlite_before_acquireto install a per-backend SQLxbefore_acquirecallback (composes with the idle-ping shorthand: idle-ping first, then the callback), plus the corresponding getters #3143 - Add
MigratorTrait::get_pending_migrations_read_only/get_applied_migrations_read_only/get_migration_with_status_read_only(and thewith-selfequivalents) — query migration status without runningCREATE TABLE, so a database user without DDL privileges can check pending migrations; if the migration table does not exist, all migrations are reported as pending #3144
Bug Fixes
-
Require
TransactionTrait::Transactionto be a fixed point, fixing nested-transaction recursion (E0275/future_not_send) in#[sea_orm::model]generated save methods #3153Compatibility note: if you implement
TransactionTraityourself,Selfmust beSync, and yourTransactiontype must beSendand its own transaction type (Transaction::Transaction = Transaction). Implementations delegating toDatabaseConnection/DatabaseTransaction, and virtually all#[async_trait]implementations, already satisfy this. Callers are unaffected.
Upgrades
- Loco examples upgraded to
loco-rs1.0 (which runs on SeaORM 2.0 stable) #3152
Release notes
Open source →ActiveValuehelpers (set_unset,is_set_and,as_option),Paginator::set_page,before_acquirepool hooks, read-only migration status queries, nested-transaction recursion fix - Add
-
2.0.019 Jul 2026Release notes
Open source →SeaORM 2.0.0
SeaORM 2.0 is the first stable release of the 2.x line. It reworks how entities,
relations, and ActiveModels are defined and used, adds an entity-first workflow,
introduces role-based access control, and brings the library onto SeaQuery 1.0 and
SQLx 0.9.The full, itemized changelog for the 2.0 series (all release candidates included)
is in CHANGELOG.md.Highlights
New entity format
Relations are now declared directly on the
Modelstruct with#[sea_orm::model],
replacing the separateRelationenum andRelatedimpls.#[sea_orm::model] #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "user")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub name: String, #[sea_orm(has_one)] pub profile: HasOne<super::profile::Entity>, #[sea_orm(has_many)] pub posts: HasMany<super::post::Entity>, }
See the new entity format walk-through.
BelongsTorelation type with compile-time cardinalityA
belongs_torelation can be typedBelongsTo<Entity>(required) or
BelongsTo<Option<Entity>>(optional), encoding the foreign-key cardinality in the
type and paired with the write-sideActiveBelongsTo. The macro validates the type
against the nullability of thefromcolumns at compile time.BelongsTois the
recommended type forbelongs_to; the legacyHasOne<Entity>field type remains
supported for backward compatibility. (#3118)Strongly-typed columns
Filter with the typed
COLUMNconstant for compile-time type safety, alongside the
existingColumnenum.user::Entity::find().filter(user::COLUMN.name.contains("Bob"))
Nested ActiveModel
Build and persist an entity together with its related rows in one expression, and
push has-many children onto a loaded model.let bob = user::ActiveModel::builder() .set_name("Bob") .set_email("[email protected]") .set_profile(profile::ActiveModel::builder().set_picture("Tennis")) .insert(db) .await?;
See nested ActiveModel.
Entity Loader
Load an entity together with its relations, including nested relations, in a single
call.let user = user::Entity::load() .filter_by_id(12) .with(profile::Entity) .with((post::Entity, comment::Entity)) .one(db) .await?;
Entity-first workflow
Create tables directly from entity definitions via the schema registry, without
writing a migration first.db.get_schema_registry("my_crate::*").sync(db).await?;
See the entity-first workflow.
Role-Based Access Control
A table-scoped, hierarchical RBAC engine with a query auditor and a
RestrictedConnectionthat implementsConnectionTraitand enforces permissions on
all Entity operations (including complex joins, insert-select, and CTE queries).
(#2683)Overhauled
insert_manyinsert_manyno longer shares a helper struct with single insert. Panic-prone APIs
were removed, empty input returnsNone/vec![]on exec, and the newInsertMany
helper exposeslast_insert_id: Option<Value>. (#2628)Synchronous SeaORM
The
sea-orm-synccrate provides a synchronous SeaORM backed byrusqlite, mirroring
the async API with async/await stripped away.Upgrading from 1.x
Follow the 1.0 to 2.0 migration guide
and the 2.0 walk-through.Notable breaking changes to be aware of:
- Expression methods like
.eq(),.like(),.contains()now require
use sea_orm::ExprTrait;in scope. Also read
SeaQuery's breaking changes. execute/query_one/query_all/streamnow take a SeaQuery statement; the
raw-SQL variants areexecute_raw/query_one_raw/query_all_raw/stream_raw.- PostgreSQL auto-increment columns now use
GENERATED BY DEFAULT AS IDENTITYinstead
ofserial; opt back in withoption-postgres-use-serialif needed. - SQLite maps both
IntegerandBigIntegertointeger. DeriveValueTypenow also derivesNotU8,IntoActiveValue, andTryFromU64;
remove any manual implementations to avoid conflicts.- Removed the
runtime-actixfeature alias (useruntime-tokio); removed
DeriveCustomColumnanddefault_as_str.
Dependencies
- SeaQuery 1.0
- SQLx 0.9
- sea-schema 0.18
Release notes
Open source →Release Candidates
- 2.0.0-rc.43 —
BelongsTorelation type (opt-in, compile-time FK cardinality), CLI generation-option errors,has_relatedCondition::any()& PG enum-array codegen fixes - 2.0.0-rc.42 — typed value arrays,
HasOnereplace/delete,ActiveHasOne/ActiveHasManyrename, codegenColumnTypefixes - 2.0.0-rc.41 —
SelectFourMany,update_without_returning,cargo binstall sea-orm-cli, junctionActiveModelBehavior& schema-sync PG-schema fixes - 2.0.0-rc.40 - Restore pgvector binding with SQLx 0.9
- 2.0.0-rc.39 - SeaQuery 1.0, SQLx 0.9, async transaction helpers
- 2.0.0-rc.38 —
find_both_related,set_ne, pool options, schema sync fixes - 2.0.0-rc.37 — ER Diagram Generation
- 2.0.0-rc.36 — Per-migration transaction control
- 2.0.0-rc.35 — SQLite transaction modes, DeriveIntoActiveModel extensions, Decimal64/Bytes, schema sync fix
- 2.0.0-rc.34 — Arrow/Parquet support,
try_from_u64for DeriveValueType - 2.0.0-rc.32 —
MigratorTraitwithself, PostgreSQLapplication_name - 2.0.0-rc.31 —
ne_all, typedTextUuid, COUNT overflow fix - 2.0.0-rc.30 — Maintenance release,
sea-querybump - 2.0.0-rc.29 — Tracing spans, UUID-as-TEXT, relation filtering, LEFT JOIN fix
- 2.0.0-rc.28 —
sqlx-allin migration,set_if_not_equals_and, auto_increment for String/Uuid PKs - 2.0.0-rc.27 —
DeriveValueTypeimplementsNotU8for PostgreSQL arrays - 2.0.0-rc.26 —
postgres-use-serial-pkfeature for legacy serial PKs - 2.0.0-rc.25 — Value system restoration,
sea-querybump - 2.0.0-rc.24 —
sea-querybump to rc.27 - 2.0.0-rc.23 —
DeriveValueTypeimplementsIntoActiveValue, removeNotU8 - 2.0.0-rc.22 —
DatabaseExecutorunified type, value array refactor - 2.0.0-rc.21 — Rusqlite /
sea-orm-synccrate,existson PaginatorTrait - 2.0.0-rc.20 — Stringy newtypes, M2M self-ref, nullable columns, bug fixes
New Features
-
Split
belongs_tofromhas_onewith a newBelongsTorelation type https://github.com/SeaQL/sea-orm/pull/3118A
belongs_torelation can now be typedBelongsTo<Entity>(required) orBelongsTo<Option<Entity>>(optional), encoding the foreign-key cardinality in the type, paired with the write-side companionActiveBelongsTo.BelongsTois the recommended type forbelongs_to; the legacyHasOne<Entity>field type remains supported for backward compatibility. -
Role Based Access Control https://github.com/SeaQL/sea-orm/pull/2683
- a hierarchical RBAC engine that is table scoped
- a user has 1 (and only 1) role
- a role has a set of permissions on a set of resources
- permissions here are CRUD operations and resources are tables
- but the engine is generic so can be used for other things
- roles have hierarchy, and so can inherit permissions
- there is a wildcard
*to grant all permissions or resources - individual users can have rules override
- a set of Entities to load / store the access control rules to / from database
- a query auditor that dissect queries for necessary permissions (implemented in SeaQuery)
- integration of RBAC into SeaORM in form of
RestrictedConnection. it implementsConnectionTrait, and will audit all queries and perform permission check, and reject them accordingly. all Entity operations except raw SQL are supported. complex joins, insert select from, and even CTE queries are supported.
- a hierarchical RBAC engine that is table scoped
// load rules from database db_conn.load_rbac().await?; // admin can create bakery let db = db_conn.restricted_for(admin)?; let seaside_bakery = bakery::ActiveModel { name: Set("SeaSide Bakery".to_owned()), ..Default::default() }; assert!(Bakery::insert(seaside_bakery).exec(&db).await.is_ok()); // public cannot create bakery let db = db_conn.restricted_for(public)?; assert!(matches!( Bakery::insert(bakery::ActiveModel::default()) .exec(&db) .await, Err(DbErr::AccessDenied { .. }) ));- Overhauled
Entity::insert_many. We've made a number of changes https://github.com/SeaQL/sea-orm/pull/2628- removed APIs that can panic
- new helper struct
InsertMany,last_insert_idis nowOption<Value> - on empty iterator,
Noneorvec![]is returned on exec operations TryInsertAPI is unchanged
Previously,
insert_manyshares the same helper struct withinsert_one, which led to an awkard API.let res = Bakery::insert_many(std::iter::empty()) .on_empty_do_nothing() // <- you need to add this .exec(db) .await; assert!(matches!(res, Ok(TryInsertResult::Empty)));last_insert_idis nowOption<Value>:struct InsertManyResult<A: ActiveModelTrait> { pub last_insert_id: Option<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>, }Which means the awkardness is removed:
let res = Entity::insert_many::<ActiveModel, _>([]).exec(db).await; assert_eq!(res?.last_insert_id, None); // insert nothing return None let res = Entity::insert_many([ActiveModel { id: Set(1) }, ActiveModel { id: Set(2) }]) .exec(db) .await; assert_eq!(res?.last_insert_id, Some(2)); // insert something return SomeSame on conflict API as before:
let res = Entity::insert_many([ActiveModel { id: Set(3) }, ActiveModel { id: Set(4) }]) .on_conflict_do_nothing() .exec(db) .await; assert!(matches!(conflict_insert, Ok(TryInsertResult::Conflicted)));Exec with returning now returns a
Vec<Model>, so it feels intuitive:assert!( Entity::insert_many::<ActiveModel, _>([]) .exec_with_returning(db) .await? .is_empty() // no footgun, nice ); assert_eq!( Entity::insert_many([ ActiveModel { id: NotSet, value: Set("two".into()), } ]) .exec_with_returning(db) .await .unwrap(), [ Model { id: 2, value: "two".into(), } ] );- Improved utility of
ActiveModel::from_json. Consider the following Entity https://github.com/SeaQL/sea-orm/pull/2599
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "cake")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, // <- not nullable pub name: String, }Previously, the following would result in error "missing field
id":assert!( cake::ActiveModel::from_json(json!({ "name": "Apple Pie", })).is_err(); );Now, the ActiveModel will be partially filled:
assert_eq!( cake::ActiveModel::from_json(json!({ "name": "Apple Pie", })) .unwrap(), cake::ActiveModel { id: NotSet, name: Set("Apple Pie".to_owned()), } );- A full
Modelcan now be used asPartialModelin nested query https://github.com/SeaQL/sea-orm/pull/2642
#[derive(DerivePartialModel)] #[sea_orm(entity = "cake::Entity")] struct Cake { id: i32, name: String, #[sea_orm(nested)] bakery: Option<bakery::Model>, } let cake: Cake = cake::Entity::find() .left_join(bakery::Entity) .order_by_asc(cake::Column::Id) .into_partial_model() .one(&ctx.db) .await? .unwrap(); assert_eq!(cake.id, 13); assert_eq!(cake.name, "Cheesecake"); assert_eq!( cake.bakery.unwrap(), bakery::Model { id: 42, name: "cool little bakery".to_string(), } );- Wrapper type derived with
DeriveValueTypecan now be used as primary key https://github.com/SeaQL/sea-orm/pull/2643
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "my_value_type")] pub struct Model { #[sea_orm(primary_key)] pub id: MyInteger, } #[derive(Clone, Debug, PartialEq, Eq, DeriveValueType)] pub struct MyInteger(pub i32); // only for i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64- You can now define unique keys that span multiple columns in Entity https://github.com/SeaQL/sea-orm/pull/2651
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "lineitem")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, #[sea_orm(unique_key = "item")] pub order_id: i32, #[sea_orm(unique_key = "item")] pub cake_id: i32, } let stmts = Schema::new(backend).create_index_from_entity(lineitem::Entity); assert_eq!( stmts[0], Index::create() .name("idx-lineitem-item") .table(lineitem::Entity) .col(lineitem::Column::OrderId) .col(lineitem::Column::CakeId) .unique() .take() ); assert_eq!( backend.build(stmts[0]), r#"CREATE UNIQUE INDEX "idx-lineitem-item" ON "lineitem" ("order_id", "cake_id")"# );- Overhauled
ConnectionTraitAPI:execute,query_one,query_all,streamnow takes in SeaQuery statement instead of raw SQL statement https://github.com/SeaQL/sea-orm/pull/2657
// old let query: SelectStatement = Entity::find().filter(..).into_query(); let backend = self.db.get_database_backend(); let stmt = backend.build(&query); let rows = self.db.query_all(stmt).await?; // new let query: SelectStatement = Entity::find().filter(..).into_query(); let rows = self.db.query_all(&query).await?;- Added
raw_sqlmacro for ergonomic parameter injection
#[derive(FromQueryResult)] struct Cake { name: String, #[sea_orm(nested)] bakery: Option<Bakery>, } #[derive(FromQueryResult)] struct Bakery { #[sea_orm(alias = "bakery_name")] name: String, } let cake_ids = [2, 3, 4]; // expanded by the `..` operator let cake: Option<Cake> = Cake::find_by_statement(raw_sql!( Sqlite, r#"SELECT "cake"."name", "bakery"."name" AS "bakery_name" FROM "cake" LEFT JOIN "bakery" ON "cake"."bakery_id" = "bakery"."id" WHERE "cake"."id" IN ({..cake_ids})"# )) .one(db) .await?;- Added
consolidatemethod toSelectThree. This output has different shape depending on the topology of the join.
// Order -> Customer // -> Lineitem let items: Vec<(order::Model, Option<customer::Model>, Option<lineitem::Model>)> = order::Entity::find() .find_also_related(customer::Entity) .find_also_related(lineitem::Entity) .order_by_asc(order::Column::Id) .order_by_asc(lineitem::Column::Id) .all(&ctx.db) .await?; // flat result assert_eq!( items, vec![ (order, Some(customer), Some(line_1)), (order, Some(customer), Some(line_2)), ] ); let items: Vec<(order::Model, Vec<customer::Model>, Vec<lineitem::Model>)> = order::Entity::find() .find_also_related(customer::Entity) .find_also_related(lineitem::Entity) .order_by_asc(order::Column::Id) .order_by_asc(lineitem::Column::Id) .consolidate() // <- .all(&ctx.db) .await?; // consolidated by order assert_eq!( items, vec![( order, vec![customer], vec![line_1, line_2] )] ); // Order -> Lineitem -> Cake let items: Vec<(order::Model, Option<lineitem::Model>, Option<cake::Model>)> = order::Entity::find() .find_also_related(lineitem::Entity) .and_also_related(cake::Entity) .order_by_asc(order::Column::Id) .order_by_asc(lineitem::Column::Id) .all(&ctx.db) .await?; // flat result assert_eq!( items, vec![ (order, Some(line_1), Some(cake_1)), (order, Some(line_2), Some(cake_2)), ] ); let items: Vec<(order::Model, Vec<(lineitem::Model, Vec<cake::Model>)>)> = order::Entity::find() .find_also_related(lineitem::Entity) .and_also_related(cake::Entity) .order_by_asc(order::Column::Id) .order_by_asc(lineitem::Column::Id) .consolidate() // <- .all(&ctx.db) .await?; // consolidated by order first, then by line assert_eq!( items, vec![( order, vec![(line_1, vec![cake_1]), (line_2, vec![cake_2])] )] );- Added
Select::has_related
// cake -> fruit: find all cakes containing mango assert_eq!( cake::Entity::find() .has_related(fruit::Entity, fruit::Column::Name.eq("Mango")) .build(DbBackend::Sqlite) .to_string(), [ r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, r#"WHERE EXISTS(SELECT 1 FROM "fruit""#, r#"WHERE "fruit"."name" = 'Mango'"#, r#"AND "cake"."id" = "fruit"."cake_id")"#, ] .join(" ") ); // cake -> cake_filling -> filling: find all cakes with orange fillings assert_eq!( cake::Entity::find() .has_related(filling::Entity, filling::Column::Name.eq("Marmalade")) .build(DbBackend::Sqlite) .to_string(), [ r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, r#"WHERE EXISTS(SELECT 1 FROM "filling""#, r#"INNER JOIN "cake_filling" ON "cake_filling"."filling_id" = "filling"."id""#, r#"WHERE "filling"."name" = 'Marmalade'"#, r#"AND "cake"."id" = "cake_filling"."cake_id")"#, ] .join(" ") );- Support self-referencing relations in loader
#[sea_orm::model] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "staff")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub name: String, pub reports_to_id: Option<i32>, #[sea_orm(self_ref, relation_enum = "ReportsTo", from = "reports_to_id", to = "id")] pub reports_to: HasOne<Entity>, } // Entity Loader let staff = staff::Entity::load() .with(staff::Relation::ReportsTo) .all(db) .await?; assert_eq!(staff[0].name, "Alan"); assert_eq!(staff[0].reports_to, None); assert_eq!(staff[1].name, "Ben"); assert_eq!(staff[1].reports_to.as_ref().unwrap().name, "Alan"); assert_eq!(staff[2].name, "Alice"); assert_eq!(staff[2].reports_to.as_ref().unwrap().name, "Alan"); // Model Loader let staff = staff::Entity::find().all(db).await?; let reports_to = staff .load_self(staff::Entity, staff::Relation::ReportsTo, db) .await?; assert_eq!(staff[0].name, "Alan"); assert_eq!(reports_to[0], None); assert_eq!(staff[1].name, "Ben"); assert_eq!(reports_to[1].unwrap().name, "Alan"); assert_eq!(staff[2].name, "Alice"); assert_eq!(reports_to[2].unwrap().name, "Alan");- Strongly-typed column https://github.com/SeaQL/sea-orm/pull/2794
// old user::Entity::find().filter(user::Column::Name.contains("Bob")) // new user::Entity::find().filter(user::COLUMN.name.contains("Bob")) // compile error: the trait `From<{integer}>` is not implemented for `String` user::Entity::find().filter(user::COLUMN.name.like(2))- Unix timestamp column type that will be mapped to big integer in database
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "access_log")] pub struct Model { .. // with `chrono` crate pub ts: ChronoUnixTimestamp, pub ms: ChronoUnixTimestampMillis, .. // with `time` crate pub ts: TimeUnixTimestamp, pub ms: TimeUnixTimestampMillis, }-
Nested ActiveModel (ActiveModelEx) and cascade operations https://github.com/SeaQL/sea-orm/pull/2818
The following operation saves a new set of user + profile + post + tag + post_tag into the database atomically:
let user = user::ActiveModel::builder() .set_name("Bob") .set_email("[email protected]") .set_profile(profile::ActiveModel::builder().set_picture("image.jpg")) .add_post( post::ActiveModel::builder() .set_title("Nice weather") .add_tag(tag::ActiveModel::builder().set_tag("sunny")), ) .save(db) .await?;Enhancements
- Added
serdefeature TextUuidnow derivesSerializeandDeserializewhen theserdefeature is enabled- [sea-orm-cli] Added
--column-extra-deriveshttps://github.com/SeaQL/sea-orm/pull/2212 - [sea-orm-cli] Added
--big-integer-type=i32to use i32 for bigint (for SQLite) - [sea-orm-cli] Fix codegen to not generate relations to filtered entities https://github.com/SeaQL/sea-orm/pull/2913
- [sea-orm-cli] Added
--experimental-preserve-user-modificationshttps://github.com/SeaQL/sea-orm/pull/2755 https://github.com/SeaQL/sea-orm/pull/2964 - [sea-orm-migration] Add custom connection entrypoint to migration CLI https://github.com/SeaQL/sea-orm/pull/3035
- Added
Model::try_set - Added new error variant
BackendNotSupported. Previously, it panics with e.g. "Database backend doesn't support RETURNING" https://github.com/SeaQL/sea-orm/pull/2630
let result = cake::Entity::insert_many([]) .exec_with_returning_keys(db) .await; if db.support_returning() { // Postgres and SQLite assert_eq!(result.unwrap(), []); } else { // MySQL assert!(matches!(result, Err(DbErr::BackendNotSupported { .. }))); }- Added new error variant
PrimaryKeyNotSet. Previously, it panics with "PrimaryKey is not set" https://github.com/SeaQL/sea-orm/pull/2627
assert!(matches!( Update::one(cake::ActiveModel { ..Default::default() }) .exec(&db) .await, Err(DbErr::PrimaryKeyNotSet { .. }) ));- Remove panics in
Schema::create_enum_from_active_enumhttps://github.com/SeaQL/sea-orm/pull/2634
fn create_enum_from_active_enum<A>(&self) -> Option<TypeCreateStatement> // method can now return None- Added
ColumnTrait::eq_anyas a shorthand for the= ANYoperator. Postgres only.
assert_eq!( cake::Entity::find() .filter(cake::Column::Id.eq_any(vec![4, 5])) .build(DbBackend::Postgres) .to_string(), r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = ANY(ARRAY [4,5])"# );- Added
ActiveModelTrait::try_set
pub trait ActiveModelTrait { /// old: set the Value of a ActiveModel field, panic if failed fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) { self.try_set(c, v).unwrap_or_else(|e| panic!(..)) } /// new: same as above but non-panicking fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>; }Linkedcan now be used in partial select, in caseRelatedcannot be defined
pub struct ToBakery; impl Linked for ToBakery { type FromEntity = super::cake::Entity; type ToEntity = super::bakery::Entity; fn link(&self) -> Vec<RelationDef> { vec![Relation::Bakery.def()] } } #[derive(Debug, DerivePartialModel)] #[sea_orm(entity = "cake::Entity", into_active_model)] struct Cake2 { id: i32, name: String, #[sea_orm(nested, alias = "r0")] bakery: Option<Bakery>, #[sea_orm(skip)] ignore: Ignore, } let cake2: Cake2 = cake::Entity::find() .left_join_linked(ToBakery) .order_by_asc(cake::Column::Id) .into_partial_model() .one(&ctx.db) .await? .unwrap();RelationDefnow implementsClone.on_conditionis changed toArcbut this is a minor breaking change.- Added
extraon column attribute:
#[cfg(feature = "with-rust_decimal")] #[sea_orm(extra = "CHECK (price > 0)")] pub price: Decimal, // results in: ColumnDef::new("price") .decimal() .not_null() .extra("CHECK (price > 0)"),- Added
ColumnTrait::avg, in addition tosum,min,maxetc
let average: Decimal = order::Entity::find() .select_only() .column_as(order::Column::Total.avg(), "avg") .into_tuple() .one(&ctx.db) .await? .unwrap();SchemaBuilder::synccan now be used in migrations
#[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { let db = manager.get_connection(); db.get_schema_builder() .register(note::Entity) .sync(db) .await } }- Allowed None for
max_lifetimeandidle_timeoutParameters https://github.com/SeaQL/sea-orm/pull/2748 - Try to parse
u32in Postgres asi32https://github.com/SeaQL/sea-orm/pull/2753 DeriveActiveEnumnow also implIntoActiveValuehttps://github.com/SeaQL/sea-orm/issues/1972DeriveValueTypenow also supports any structs that can be converted to / from string https://github.com/SeaQL/sea-orm/issues/2811
#[derive(Copy, Clone, Debug, PartialEq, Eq, DeriveValueType)] #[sea_orm(value_type = "String")] pub struct Tag3 { pub i: i64, } impl std::fmt::Display for Tag3 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.i) } } impl std::str::FromStr for Tag3 { type Err = std::num::ParseIntError; fn from_str(s: &str) -> Result<Self, Self::Err> { let i: i64 = s.parse()?; Ok(Self { i }) } }- Fix
DeriveIntoActiveModelonOption<T>fields https://github.com/SeaQL/sea-orm/pull/2926
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "fruit")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub name: String, pub cake_id: Option<i32>, } #[derive(DeriveIntoActiveModel)] #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")] struct PartialFruit { cake_id: Option<i32>, } assert_eq!( PartialFruit { cake_id: Some(1) }.into_active_model(), fruit::ActiveModel { id: NotSet, name: NotSet, cake_id: Set(Some(1)) } ); assert_eq!( PartialFruit { cake_id: None }.into_active_model(), fruit::ActiveModel { id: NotSet, name: NotSet, cake_id: NotSet } );FromQueryResultnow supports nullable nested model https://github.com/SeaQL/sea-orm/pull/2845
#[derive(FromQueryResult)] struct CakeWithOptionalBakeryModel { #[sea_orm(alias = "cake_id")] id: i32, #[sea_orm(alias = "cake_name")] name: String, #[sea_orm(nested)] bakery: Option<bakery::Model>, // can be null }- Added
try_from_u64toDeriveValueTypehttps://github.com/SeaQL/sea-orm/pull/2958
// Test for try_from_u64 attribute with type alias type UserId = i32; #[derive(Clone, Debug, PartialEq, Eq, DeriveValueType)] #[sea_orm(try_from_u64)] pub struct MyUserId(pub UserId);- Arrow / Parquet support https://github.com/SeaQL/sea-orm/pull/2957
- Added
ArrowSchema,DeriveArrowSchema - Support decimal with different formats
- Support timestamp with different timezone / resolution
- Added parquet example
- Added
- Support
HashMapandBTreeMapfor JSON columns viaTryGetableFromJsonhttps://github.com/SeaQL/sea-orm/pull/3009 - Derive macros now inherit the visibility of the input type for generated items such as
Entity,Column,PrimaryKey, andActiveModelhttps://github.com/SeaQL/sea-orm/pull/3029
Bug Fixes
- [sea-orm-migration] PostgreSQL
drop_everythingnow drops custom types withCASCADE
Breaking Changes
Please read SeaQuery's breaking changes as well. But for most compile errors, you can simply add
use sea_orm::ExprTrait;in scope.error[E0599]: no method named `like` found for enum `sea_query::Expr` in the current scope | | Expr::col((self.entity_name(), *self)).like(s) | | fn like<L>(self, like: L) -> Expr | ---- the method is available for `sea_query::Expr` here | = help: items from traits can only be used if the trait is in scope help: trait `ExprTrait` which provides `like` is implemented but not in scope; perhaps you want to import it | -> + use sea_orm::ExprTrait;error[E0308]: mismatched types --> src/sqlite/discovery.rs:27:57 | | .and_where(Expr::col(Alias::new("type")).eq("table")) | -- ^^^^^^^ expected `&Expr`, found `&str` | | | arguments to this method are incorrect | = note: expected reference `&sea_query::Expr` found reference `&'static str`error[E0308]: mismatched types | 390 | Some(Expr::col(Name).eq(PgFunc::any(query.symbol))) | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&Expr`, found `FunctionCall` | | | arguments to this method are incorrect | note: method defined here --> /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library/core/src/cmp.rs:254:8error[E0277]: the trait bound `sea_orm::Condition: From<bool>` is not satisfied | 367 | .add_option(option) | ---------- ^^^^^^ the trait `From<bool>` is not implemented for `sea_orm::Condition` | | | required by a bound introduced by this call | = note: required for `bool` to implement `Into<sea_orm::Condition>`- Removed
runtime-actixfeature flag. It's been an alias ofruntime-tokiofor more than a year, so there should be no impact. - Enabled
sqlite-use-returning-for-3_35by default. SQLite3.35was released in 2021, it should be the default by now. - Now implemented
impl<T: ModelTrait + FromQueryResult> PartialModelTrait for T, there may be a potential conflict https://github.com/SeaQL/sea-orm/pull/2642 - Now
DeriveValueTypewill alsoTryFromU64if applicable, there may be a potential conflict https://github.com/SeaQL/sea-orm/pull/2643 - Now
DeriveValueTypealso implIntoActiveValueandNotU8, there may be a potential conflict - Added
TryIntoModelandSerializeto trait bounds ofActiveModel::from_json. There should be no impact if your models are derived withDeriveEntityModelhttps://github.com/SeaQL/sea-orm/pull/2599
fn from_json(mut json: serde_json::Value) -> Result<Self, DbErr> where Self: TryIntoModel<<Self::Entity as EntityTrait>::Model>, <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>, for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: serde::de::Deserialize<'de> + serde::Serialize,DerivePartialModelnow implementFromQueryResultby default, so there may be a potential conflict. RemoveFromQueryResultin these cases https://github.com/SeaQL/sea-orm/pull/2653
error[E0119]: conflicting implementations of trait `sea_orm::FromQueryResult` for type `CakeWithFruit` | > | #[derive(DerivePartialModel, FromQueryResult)] | ------------------ ^^^^^^^^^^^^^^^ conflicting implementation for `CakeWithFruit`- Changed
IdenStaticandEntityNamedefinition https://github.com/SeaQL/sea-orm/pull/2667
trait IdenStatic { fn as_str(&self) -> &'static str; // added static lifetime } trait EntityName { fn table_name(&self) -> &'static str; // added static lifetime }- Removed
DeriveCustomColumnanddefault_as_strhttps://github.com/SeaQL/sea-orm/pull/2667
// This is no longer supported: #[derive(Copy, Clone, Debug, EnumIter, DeriveCustomColumn)] pub enum Column { Id, Name, } impl IdenStatic for Column { fn as_str(&self) -> &str { match self { Self::Name => "my_name", _ => self.default_as_str(), } } } // Do the following instead: #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] pub enum Column { Id, #[sea_orm(column_name = "my_name")] Name, }execute,query_one,query_all,streamnow takes in SeaQuery statement instead of raw SQL statement. a new set of methodsexecute_raw,query_one_raw,query_all_raw,stream_rawis added https://github.com/SeaQL/sea-orm/pull/2657
--> src/executor/paginator.rs:53:38 | > | let rows = self.db.query_all(stmt).await?; | --------- ^^^^ expected `&_`, found `Statement` | | | arguments to this method are incorrect | = note: expected reference `&_` found struct `statement::Statement`let backend = self.db.get_database_backend(); let stmt = backend.build(&query); // change to: let rows = self.db.query_all_raw(stmt).await?; // if the query is a SeaQuery statement, then just do this: let rows = self.db.query_all(&query).await?; // no need to build queryDatabaseConnectionis changed from enum to struct. The original enum is moved intoDatabaseConnection::inner. The new enum is namedDatabaseConnectionTypehttps://github.com/SeaQL/sea-orm/pull/2671
error[E0599]: no associated item named `Disconnected` found for struct `db_connection::DatabaseConnection` in the current scope --> src/database/db_connection.rs:137:33 | > | pub struct DatabaseConnection { | ----------------------------- associated item `Disconnected` not found for this struct ... > | DatabaseConnection::Disconnected => Err(conn_err("Disconnected")), | ^^^^^^^^^^^^ associated item not found in `DatabaseConnection`match conn.inner { DatabaseConnectionType::Disconnected => (), _ => (), }DeleteOneandUpdateOneno longer implementQueryFilterandQueryTraitdirectly. Those implementations could expose an incomplete SQL query with an incomplete condition that touches too many records. To generate the right condition, we must make sure that the primary key is set on the inputActiveModel. If you need to access the generated SQL query, convert intoValidatedDeleteOne/ValidatedUpdateOnefirst.
error[E0599]: no method named `build` found for struct `query::update::UpdateOne` in the current scope --> src/entity/column.rs:607:22 | > | / Update::one(active_model) > | | .build(DbBackend::Postgres) | | -^^^^^ method not found in `UpdateOne<A>` | |_____________________| |Call the
validate()method:Update::one(active_model) + .validate()? .build(DbBackend::Postgres)- Removed
DbBackend::get_query_builder()becauseQueryBuilderis not longer object safe.
- fn get_query_builder(&self) -> Box<dyn QueryBuilder>- A number of methods has been removed from
SelectTwoMany:into_partial_model,into_json,stream. These methods are same as those inSelectTwo. Please useCake::find().find_also_related(Fruit).into_json()instead. - The
delete_by_idmethod has changed to returningDeleteOneinstead ofDeleteMany. It doesn't change normalexecusage, but would change return type ofexec_with_returningtoOption<Model>
fn delete_by_id<T>(values: T) -> DeleteMany<Self> // old fn delete_by_id<T>(values: T) -> ValidatedDeleteOne<Self> // newDeriveActiveEnumnow also automatically implIntoActiveValue, if you have a custom impl before, there would be a collisionwith-bigdecimalis now removed from default featuresRuntimeErr::SqlxErroris now held inArcto makeDbErrclonable and smaller:
pub enum RuntimeErr { SqlxError(Arc<sqlx::error::Error>),Upgrades
- Upgraded Rust Edition to 2024 https://github.com/SeaQL/sea-orm/pull/2596
- Upgraded
strumto0.27
- Expression methods like
-
2.0.0-rc.4315 Jul 2026 pre-releaseRelease notes
Open source →Release Notes: SeaORM 2.0.0-rc.43
(since 2.0.0-rc.42)
New Features
BelongsTorelation type (#3118, #3133, #3134)A dedicated
BelongsTo<E>/BelongsTo<Option<E>>type forbelongs_torelations,
alongside the existingHasOne. Cardinality lives in the type parameter, so the
foreign-key nullability is expressed — and checked — at compile time:BelongsTo<E>— the FK isNOT NULL; the relation cannot be detached (there is
no way to set it to "none" on the active side), so orphaning a required parent is
a compile error rather than a runtime constraint violation.BelongsTo<Option<E>>— the FK is nullable; the relation can be detached, which
nulls the FK on save.
The cardinality is validated against the FK columns when the entity is derived:
BelongsTo<Entity>requires everyfromcolumn to beNOT NULL, and
BelongsTo<Option<Entity>>requires at least one nullablefromcolumn — a mismatch
is a compile error. Composite foreign keys with mixed nullability detach by nulling
only their nullable columns.#[sea_orm(belongs_to, from = "user_id", to = "id")] pub author: BelongsTo<super::user::Entity>, // required #[sea_orm(belongs_to, from = "bakery_id", to = "id")] pub bakery: BelongsTo<Option<super::bakery::Entity>>, // optional
The active side is
ActiveBelongsTo<..>, mirroringActiveHasOne/ActiveHasMany.HasOnestill works forbelongs_to— no migration required (#3133)Adopting
BelongsTois opt-in. Abelongs_tofield may keep its existing
HasOne<Entity>type; it continues to compile and behave as before. UseBelongsTo
when you want the compile-time cardinality guarantee; otherwise nothing changes.Enhancements
CLI lists valid options on generation error (#3131)
sea-orm-cli generate entitynow prints the valid choices when an invalid option
value is supplied, instead of only reporting that the value was rejected.Bug Fixes
has_relatedwith aCondition::any()filter (#3126)has_relatedwrapped the caller's condition and then added the mandatory FK/join
condition to it. When the caller passed aCondition::any()(anORgroup), the
join condition was folded into that disjunction, so the relation constraint was no
longer guaranteed. The caller's condition is now wrapped inCondition::all()first,
yielding(caller condition) AND (fk join)regardless ofany()/all().Entity codegen for PostgreSQL enum array columns (#3120)
Array-of-enum columns were generated as scalar active-enum fields because the type
resolver unwrappedArray(Enum)toEnum. Array columns now route through the
full type resolver, soenum[]columns generateVec<Enum>fields.Compatibility Notes
belongs_torelations may now be typedBelongsTo<Entity>/
BelongsTo<Option<Entity>>. This is opt-in — existingHasOne-typedbelongs_to
fields are unchanged and still supported.sea-orm-clicontinues to generate the
HasOneform.- The compile-time detach guarantee applies only to
BelongsTo<Entity>(non-null);
it is a property of the type, so it costs nothing at runtime. - A
BelongsTofield's type parameter must match its FK nullability (checked when
the entity is derived). This only affects code that opts intoBelongsTo. - The nested-
ActiveModelrelation types remain semver-exempt (unstable): rc.43
drops theirPartialEq<Option<..>>impls, so compare an empty relation with
is_unloaded_or_not_found()/is_not_found()/as_ref()rather than== None
/== Some(..).
-
2.0.0-rc.4204 Jul 2026 pre-releaseRelease notes
Open source →Release Notes: SeaORM 2.0.0-rc.42
(since 2.0.0-rc.41)
New Features
Typed value arrays via
try_getable_array(#3108, #2967)DeriveValueTypewrappers backed by aVec<_>now round-trip as native
PostgreSQL arrays: the derive generates atry_getable_arrayimplementation, so
a newtype overVec<i32>reads and writes asINTEGER[]without a manual
TryGetableimpl.#[derive(Clone, Debug, PartialEq, DeriveValueType)] pub struct Tags(Vec<String>);
Replace and delete a nested
HasOne(#3110, #3060, #3061)The active has-one type (
ActiveHasOne) gains aDeletevariant plus generated
delete_<field>/set_<field>_optionbuilders. Setting a populated has-one now
replaces the existing linked record (deleting or orphaning the old one) instead
of erroring, andDeleteremoves it on save.let mut user = user::Entity::load().filter_by_id(1).with(profile::Entity).one(db).await?.unwrap(); user.delete_profile().save(db).await?; // remove the linked profile
TryFrom<&str>for active enums (#3111)DeriveActiveEnumnow generates aTryFrom<&str>implementation, so a string
value can be parsed straight into the enum by its database string representation.let color = Color::try_from("Black")?;
Enhancements
ActiveHasOne/ActiveHasMany(renamed)The active/write-side companions to
HasOne/HasManyare renamed from
HasOneModel/HasManyModeltoActiveHasOne/ActiveHasMany, so the names
read as active-model values rather than loaded models. The read-sideHasOne/
HasManytypes are unchanged.Documented
SqlErrandDbErr::sql_err()(#2940)DbErr::sql_err()and theSqlErrvariants are documented, including how to reach
the raw driver error for backend-specific handling.if let Some(SqlErr::UniqueConstraintViolation(_)) = err.sql_err() { /* ... */ }
Schema sync warns on column-type divergence (#3106)
SchemaBuilder::sync()logs a warning when a live column's type diverges from the
entity definition instead of silently ignoring the difference.Bug Fixes
Codegen
ColumnTypecoverage (#3092)Entity generation emits compiling code for
Year,Bit,VarBit,MacAddr,
LTree, andIntervalcolumns, and forMoneycolumns carrying precision and
scale — previously these produced non-compilingColumnTypeexpressions.Skip generated columns in entity generation (#3094)
sea-orm-cli generate entityskips database-generated columns, which cannot be
inserted or updated, instead of emitting them as ordinary fields.SchemaBuilder::sync()returns aSendfuture (#3100)Regression fix:
sync()no longer returns a non-Sendfuture, so it can be used
across.awaitpoints on multi-threaded runtimes. Released together with
sea-schema 0.18.1.sea-orm-syncgeneration fixes (#3112)The
make-synctransform correctly handlesfutures_utilusage in the mock
driver, keeping the blockingsea-orm-synccrate in sync with the async source.Compatibility Notes
HasOneModel/HasManyModelare renamed toActiveHasOne/ActiveHasMany.
Update references; the read-sideHasOne/HasManyare unaffected.DbErr,UpdateResult,DeleteResult,ActiveHasOne, andActiveHasManyare
now#[non_exhaustive]; downstreammatches need a wildcard arm.- Schema sync and nested-ActiveModel relation mutation are marked unstable
(semver-exempt) while their APIs settle. - Prebuilt
sea-orm-clibinaries no longer include the Intel macOS
(x86_64-apple-darwin) target.
-
2.0.0-rc.4118 Jun 2026 pre-releaseNothing published for this version
-
2.0.0-rc.4030 May 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3930 May 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3809 Apr 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3709 Mar 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3604 Mar 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3527 Feb 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3421 Feb 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3320 Feb 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3211 Feb 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3108 Feb 2026 pre-releaseNothing published for this version
-
2.0.0-rc.3026 Jan 2026 pre-releaseNothing published for this version
-
2.0.0-rc.2925 Jan 2026 pre-releaseNothing published for this version
-
2.0.0-rc.2811 Jan 2026 pre-releaseNothing published for this version
-
2.0.0-rc.2730 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2629 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2529 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2429 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2328 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2221 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2114 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.2001 Dec 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1923 Nov 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1808 Nov 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1702 Nov 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1628 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1525 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1424 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1319 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1219 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1116 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.1011 Oct 2025 pre-releaseNothing published for this version
-
2.0.0-rc.927 Sep 2025 pre-releaseNothing published for this version
-
2.0.0-rc.823 Sep 2025 pre-releaseNothing published for this version
-
2.0.0-rc.716 Sep 2025 pre-releaseNothing published for this version
-
2.0.0-rc.631 Aug 2025 pre-releaseNothing published for this version
-
2.0.0-rc.523 Aug 2025 pre-releaseNothing published for this version
-
2.0.0-rc.421 Aug 2025 pre-releaseNothing published for this version
-
2.0.0-rc.311 Aug 2025 pre-releaseNothing published for this version
-
2.0.0-rc.211 Aug 2025 pre-release withdrawnNothing published for this version
-
2.0.0-rc.105 Jul 2025 pre-releaseNothing published for this version
-
1.2.0-rc.129 May 2025 pre-releaseNothing published for this version
-
1.1.2031 Mar 2026Nothing published for this version
-
1.1.1911 Nov 2025Release notes
Open source →Enhancements
- Add
find_linked_recursivemethod to ModelTrait https://github.com/SeaQL/sea-orm/pull/2480 - Skip drop extension type in fresh https://github.com/SeaQL/sea-orm/pull/2716
Bug Fixes
- Handle null values in
from_sqlx_*_row_to_proxy_rowfunctions https://github.com/SeaQL/sea-orm/pull/2744
- Add
-
1.1.1810 Nov 2025Nothing published for this version
-
1.1.1709 Oct 2025Release notes
Open source →New Features
- Added
map_sqlx_mysql_opts,map_sqlx_postgres_opts,map_sqlx_sqlite_optstoConnectOptionshttps://github.com/SeaQL/sea-orm/pull/2731
let mut opt = ConnectOptions::new(url); opt.map_sqlx_postgres_opts(|pg_opt: PgConnectOptions| { pg_opt.ssl_mode(PgSslMode::Require) });- Added
mariadb-use-returningto use returning syntax for MariaDB https://github.com/SeaQL/sea-orm/pull/2710 - Released
sea-orm-rocket0.6 https://github.com/SeaQL/sea-orm/pull/2732
- Added
-
1.1.1611 Sep 2025Release notes
Open source →Bug Fixes
- Fix enum casting in DerivePartialModel https://github.com/SeaQL/sea-orm/pull/2719 https://github.com/SeaQL/sea-orm/pull/2720
#[derive(DerivePartialModel)] #[sea_orm(entity = "active_enum::Entity", from_query_result, alias = "zzz")] struct PartialWithEnumAndAlias { #[sea_orm(from_col = "tea")] foo: Option<Tea>, } let sql = active_enum::Entity::find() .into_partial_model::<PartialWithEnumAndAlias>() .into_statement(DbBackend::Postgres) .sql; assert_eq!( sql, r#"SELECT CAST("zzz"."tea" AS "text") AS "foo" FROM "public"."active_enum""#, );Enhancements
- [sea-orm-cli] Use tokio (optional) instead of async-std https://github.com/SeaQL/sea-orm/pull/2721
-
1.1.1531 Aug 2025Release notes
Open source →Enhancements
- Allow
DerivePartialModelto have nested aliases https://github.com/SeaQL/sea-orm/pull/2686
#[derive(DerivePartialModel)] #[sea_orm(entity = "bakery::Entity", from_query_result)] struct Factory { id: i32, #[sea_orm(from_col = "name")] plant: String, } #[derive(DerivePartialModel)] #[sea_orm(entity = "cake::Entity", from_query_result)] struct CakeFactory { id: i32, name: String, #[sea_orm(nested, alias = "factory")] // <- new bakery: Option<Factory>, }- Add
ActiveModelTrait::try_sethttps://github.com/SeaQL/sea-orm/pull/2706
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value); /// New: a non-panicking version of above fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;Bug Fixes
- [sea-orm-cli] Fix compilation issue https://github.com/SeaQL/sea-orm/pull/2713
- Allow
-
1.1.1421 Jul 2025Release notes
Open source →Enhancements
- [sea-orm-cli] Mask sensitive ENV values https://github.com/SeaQL/sea-orm/pull/2658
Bug Fixes
FromJsonQueryResult: panic on serialization failures https://github.com/SeaQL/sea-orm/pull/2635
#[derive(Clone, Debug, PartialEq, Deserialize, FromJsonQueryResult)] pub struct NonSerializableStruct; impl Serialize for NonSerializableStruct { fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { Err(serde::ser::Error::custom( "intentionally failing serialization", )) } } let model = Model { json: Some(NonSerializableStruct), }; let _ = model.into_active_model().insert(&ctx.db).await; // panic here -
1.1.1329 Jun 2025Release notes
Open source →New Features
- [sea-orm-cli] New
--frontend-formatflag to generate entities in pure Rust https://github.com/SeaQL/sea-orm/pull/2631
// for example, below is the normal (compact) Entity: use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] #[sea_orm(table_name = "cake")] pub struct Model { #[sea_orm(primary_key)] #[serde(skip_deserializing)] pub id: i32, #[sea_orm(column_type = "Text", nullable)] pub name: Option<String> , } // this is the generated frontend model, there is no SeaORM dependency: use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Model { #[serde(skip_deserializing)] pub id: i32, pub name: Option<String> , }Enhancements
- Removed potential panics from
Loaderhttps://github.com/SeaQL/sea-orm/pull/2637
- [sea-orm-cli] New
-
1.1.1227 May 2025Release notes
Open source →Enhancements
- Make sea-orm-cli & sea-orm-migration dependencies optional https://github.com/SeaQL/sea-orm/pull/2367
- Relax TransactionError's trait bound for errors to allow
anyhow::Errorhttps://github.com/SeaQL/sea-orm/pull/2602
Bug Fixes
- Include custom
column_namein DeriveColumnColumn::from_strimpl https://github.com/SeaQL/sea-orm/pull/2603
#[derive(DeriveEntityModel)] pub struct Model { #[sea_orm(column_name = "lAsTnAmE")] last_name: String, } assert!(matches!(Column::from_str("lAsTnAmE").unwrap(), Column::LastName)); -
1.1.1107 May 2025Release notes
Open source →Enhancements
- Added
ActiveModelTrait::default_values
assert_eq!( fruit::ActiveModel::default_values(), fruit::ActiveModel { id: Set(0), name: Set("".into()), cake_id: Set(None), type_without_default: NotSet, }, );- Impl
IntoConditionforRelationDefhttps://github.com/SeaQL/sea-orm/pull/2587
// This allows using `RelationDef` directly where sea-query expects an `IntoCondition` let query = Query::select() .from(fruit::Entity) .inner_join(cake::Entity, fruit::Relation::Cake.def()) .to_owned();- Loader: retain only unique key values in the query condition https://github.com/SeaQL/sea-orm/pull/2569
- Add proxy transaction impl https://github.com/SeaQL/sea-orm/pull/2573
- [sea-orm-cli] Fix
PgVectorcodegen https://github.com/SeaQL/sea-orm/pull/2589
Bug fixes
- Quote type properly in
AsEnumcasting https://github.com/SeaQL/sea-orm/pull/2570
assert_eq!( lunch_set::Entity::find() .select_only() .column(lunch_set::Column::Tea) .build(DbBackend::Postgres) .to_string(), r#"SELECT CAST("lunch_set"."tea" AS "text") FROM "lunch_set""# // "text" is now quoted; will work for "text"[] as well );- Fix unicode string enum https://github.com/SeaQL/sea-orm/pull/2218
Upgrades
- Upgrade
heckto0.5https://github.com/SeaQL/sea-orm/pull/2218 - Upgrade
sea-queryto0.32.5 - Upgrade
sea-schemato0.16.2
- Added
-
1.1.1014 Apr 2025Release notes
Open source →Upgrades
- Upgrade sqlx to 0.8.4 https://github.com/SeaQL/sea-orm/pull/2562
-
1.1.913 Apr 2025Release notes
Open source →Enhancements
- [sea-orm-macros] Use fully-qualified syntax for ActiveEnum associated type https://github.com/SeaQL/sea-orm/pull/2552
- Accept
LikeExprinlikeandnot_likehttps://github.com/SeaQL/sea-orm/pull/2549
Bug fixes
- Check if url is well-formed before parsing https://github.com/SeaQL/sea-orm/pull/2558
QuerySelect::column_asmethod cast ActiveEnum column https://github.com/SeaQL/sea-orm/pull/2551
House keeping
- Remove redundant
Expr::exprfrom internal code https://github.com/SeaQL/sea-orm/pull/2554
-
1.1.830 Mar 2025Release notes
Open source →New Features
- Implement
DeriveValueTypefor enum strings
#[derive(DeriveValueType)] #[sea_orm(value_type = "String")] pub enum Tag { Hard, Soft, } // `from_str` defaults to `std::str::FromStr::from_str` impl std::str::FromStr for Tag { type Err = sea_orm::sea_query::ValueTypeErr; fn from_str(s: &str) -> Result<Self, Self::Err> { .. } } // `to_str` defaults to `std::string::ToString::to_string`. impl std::fmt::Display for Tag { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { .. } } // you can override from_str and to_str with custom functions #[derive(DeriveValueType)] #[sea_orm(value_type = "String", from_str = "Tag::from_str", to_str = "Tag::to_str")] pub enum Tag { Color, Grey, } impl Tag { fn from_str(s: &str) -> Result<Self, ValueTypeErr> { .. } fn to_str(&self) -> &'static str { .. } }- Support Postgres Ipnetwork (under feature flag
with-ipnetwork) https://github.com/SeaQL/sea-orm/pull/2395
// Model #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "host_network")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub ipaddress: IpNetwork, #[sea_orm(column_type = "Cidr")] pub network: IpNetwork, } // Schema sea_query::Table::create() .table(host_network::Entity) .col(ColumnDef::new(host_network::Column::Id).integer().not_null().auto_increment().primary_key()) .col(ColumnDef::new(host_network::Column::Ipaddress).inet().not_null()) .col(ColumnDef::new(host_network::Column::Network).cidr().not_null()) .to_owned(); // CRUD host_network::ActiveModel { ipaddress: Set(IpNetwork::new(Ipv6Addr::new(..))), network: Set(IpNetwork::new(Ipv4Addr::new(..))), ..Default::default() }Enhancements
- Added
try_getable_postgres_array!(Vec<u8>)(to supportbytea[]) https://github.com/SeaQL/sea-orm/pull/2503
Bug fixes
- [sea-orm-codegen] Support postgres array in expanded format https://github.com/SeaQL/sea-orm/pull/2545
House keeping
- Replace
once_cellcrate withstdequivalent https://github.com/SeaQL/sea-orm/pull/2524 (available since rust 1.80)
- Implement