sea_orm/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(missing_docs)]
3#![deny(
4 missing_debug_implementations,
5 clippy::missing_panics_doc,
6 clippy::unwrap_used,
7 clippy::print_stderr,
8 clippy::print_stdout
9)]
10
11//! <div align="center">
12//!
13//! <img src="https://www.sea-ql.org/SeaORM/img/SeaORM banner.png"/>
14//!
15//! <h1>SeaORM</h1>
16//!
17//! <h3>π An async & dynamic ORM for Rust</h3>
18//!
19//! [](https://crates.io/crates/sea-orm)
20//! [](https://docs.rs/sea-orm)
21//! [](https://github.com/SeaQL/sea-orm/actions/workflows/rust.yml)
22//!
23//! </div>
24//!
25//! # SeaORM
26//!
27//! [δΈζζζ‘£](https://github.com/SeaQL/sea-orm/blob/master/README-zh.md)
28//!
29//! #### SeaORM is a relational ORM to help you build web services in Rust with the familiarity of dynamic languages.
30//!
31//! [](https://github.com/SeaQL/sea-orm/stargazers/)
32//! If you like what we do, consider starring, sharing and contributing!
33//!
34//! Please help us with maintaining SeaORM by completing the [SeaQL Community Survey 2025](https://www.sea-ql.org/community-survey/)!
35//!
36//! [](https://discord.com/invite/uCPdDXzbdv)
37//! Join our Discord server to chat with other members of the SeaQL community!
38//!
39//! ## Getting Started
40//!
41//! + [Documentation](https://www.sea-ql.org/SeaORM)
42//! + [Tutorial](https://www.sea-ql.org/sea-orm-tutorial)
43//! + [Cookbook](https://www.sea-ql.org/sea-orm-cookbook)
44//!
45//! Integration examples:
46//!
47//! + [Actix v4 Example](https://github.com/SeaQL/sea-orm/tree/master/examples/actix_example)
48//! + [Axum Example](https://github.com/SeaQL/sea-orm/tree/master/examples/axum_example)
49//! + [GraphQL Example](https://github.com/SeaQL/sea-orm/tree/master/examples/graphql_example)
50//! + [jsonrpsee Example](https://github.com/SeaQL/sea-orm/tree/master/examples/jsonrpsee_example)
51//! + [Loco TODO Example](https://github.com/SeaQL/sea-orm/tree/master/examples/loco_example) / [Loco REST Starter](https://github.com/SeaQL/sea-orm/tree/master/examples/loco_starter)
52//! + [Poem Example](https://github.com/SeaQL/sea-orm/tree/master/examples/poem_example)
53//! + [Rocket Example](https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_example) / [Rocket OpenAPI Example](https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_okapi_example)
54//! + [Salvo Example](https://github.com/SeaQL/sea-orm/tree/master/examples/salvo_example)
55//! + [Tonic Example](https://github.com/SeaQL/sea-orm/tree/master/examples/tonic_example)
56//! + [Seaography Example (Bakery)](https://github.com/SeaQL/sea-orm/tree/master/examples/seaography_example) / [Seaography Example (Sakila)](https://github.com/SeaQL/seaography/tree/main/examples/sqlite)
57//!
58//! ## Features
59//!
60//! 1. Async
61//!
62//! Relying on [SQLx](https://github.com/launchbadge/sqlx), SeaORM is a new library with async support from day 1.
63//!
64//! 2. Dynamic
65//!
66//! Built upon [SeaQuery](https://github.com/SeaQL/sea-query), SeaORM allows you to build complex dynamic queries.
67//!
68//! 3. Service Oriented
69//!
70//! Quickly build services that join, filter, sort and paginate data in REST, GraphQL and gRPC APIs.
71//!
72//! 4. Production Ready
73//!
74//! SeaORM is feature-rich, well-tested and used in production by companies and startups.
75//!
76//! ## A quick taste of SeaORM
77//!
78//! ### Entity
79//! ```
80//! # #[cfg(feature = "macros")]
81//! # mod entities {
82//! # mod fruit {
83//! # use sea_orm::entity::prelude::*;
84//! # #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
85//! # #[sea_orm(table_name = "fruit")]
86//! # pub struct Model {
87//! # #[sea_orm(primary_key)]
88//! # pub id: i32,
89//! # pub name: String,
90//! # pub cake_id: Option<i32>,
91//! # }
92//! # #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
93//! # pub enum Relation {
94//! # #[sea_orm(
95//! # belongs_to = "super::cake::Entity",
96//! # from = "Column::CakeId",
97//! # to = "super::cake::Column::Id"
98//! # )]
99//! # Cake,
100//! # }
101//! # impl Related<super::cake::Entity> for Entity {
102//! # fn to() -> RelationDef {
103//! # Relation::Cake.def()
104//! # }
105//! # }
106//! # impl ActiveModelBehavior for ActiveModel {}
107//! # }
108//! # mod cake {
109//! use sea_orm::entity::prelude::*;
110//!
111//! #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
112//! #[sea_orm(table_name = "cake")]
113//! pub struct Model {
114//! #[sea_orm(primary_key)]
115//! pub id: i32,
116//! pub name: String,
117//! }
118//!
119//! #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
120//! pub enum Relation {
121//! #[sea_orm(has_many = "super::fruit::Entity")]
122//! Fruit,
123//! }
124//!
125//! impl Related<super::fruit::Entity> for Entity {
126//! fn to() -> RelationDef {
127//! Relation::Fruit.def()
128//! }
129//! }
130//! # impl ActiveModelBehavior for ActiveModel {}
131//! # }
132//! # }
133//! ```
134//!
135//! ### Select
136//! SeaORM models one-to-many and many-to-many relationships at the Entity level.
137//! Many-to-many join can traverse the junction table in a single method call.
138//! ```
139//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
140//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
141//! // find all models
142//! let cakes: Vec<cake::Model> = Cake::find().all(db).await?;
143//!
144//! // find and filter
145//! let chocolate: Vec<cake::Model> = Cake::find()
146//! .filter(cake::Column::Name.contains("chocolate"))
147//! .all(db)
148//! .await?;
149//!
150//! // find one model
151//! let cheese: Option<cake::Model> = Cake::find_by_id(1).one(db).await?;
152//! let cheese: cake::Model = cheese.unwrap();
153//!
154//! // find related models (lazy)
155//! let fruits: Vec<fruit::Model> = cheese.find_related(Fruit).all(db).await?;
156//!
157//! // find related models (eager): works for both 1-N and M-N relations
158//! let cake_with_fruits: Vec<(cake::Model, Vec<fruit::Model>)> =
159//! Cake::find().find_with_related(Fruit).all(db).await?;
160//! # Ok(())
161//! # }
162//! ```
163//!
164//! ### Nested Select
165//!
166//! ```
167//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
168//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
169//! use sea_orm::DerivePartialModel;
170//!
171//! #[derive(DerivePartialModel)]
172//! #[sea_orm(entity = "cake::Entity")]
173//! struct CakeWithFruit {
174//! id: i32,
175//! name: String,
176//! #[sea_orm(nested)]
177//! fruit: Option<fruit::Model>, // this can be a regular or another partial model
178//! }
179//!
180//! let cakes: Vec<CakeWithFruit> = cake::Entity::find()
181//! .left_join(fruit::Entity) // no need to specify join condition
182//! .into_partial_model() // only the columns in the target struct will be selected
183//! .all(db)
184//! .await?;
185//! # Ok(())
186//! # }
187//! ```
188//!
189//! ### Insert
190//! ```
191//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
192//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
193//! let apple = fruit::ActiveModel {
194//! name: Set("Apple".to_owned()),
195//! ..Default::default() // no need to set primary key
196//! };
197//!
198//! let pear = fruit::ActiveModel {
199//! name: Set("Pear".to_owned()),
200//! ..Default::default()
201//! };
202//!
203//! // insert one
204//! let pear = pear.insert(db).await?;
205//! # Ok(())
206//! # }
207//! # async fn function2(db: &DbConn) -> Result<(), DbErr> {
208//! # let apple = fruit::ActiveModel {
209//! # name: Set("Apple".to_owned()),
210//! # ..Default::default() // no need to set primary key
211//! # };
212//! # let pear = fruit::ActiveModel {
213//! # name: Set("Pear".to_owned()),
214//! # ..Default::default()
215//! # };
216//!
217//! // insert many returning last insert id
218//! let result = Fruit::insert_many([apple, pear]).exec(db).await?;
219//! result.last_insert_id == Some(2);
220//! # Ok(())
221//! # }
222//! ```
223//!
224//! ### Insert (advanced)
225//! ```
226//! # use sea_orm::{DbConn, TryInsertResult, error::*, entity::*, query::*, tests_cfg::*};
227//! # async fn function_1(db: &DbConn) -> Result<(), DbErr> {
228//! # let apple = fruit::ActiveModel {
229//! # name: Set("Apple".to_owned()),
230//! # ..Default::default() // no need to set primary key
231//! # };
232//! # let pear = fruit::ActiveModel {
233//! # name: Set("Pear".to_owned()),
234//! # ..Default::default()
235//! # };
236//! // insert many with returning (if supported by database)
237//! let models: Vec<fruit::Model> = Fruit::insert_many([apple, pear])
238//! .exec_with_returning(db)
239//! .await?;
240//! models[0]
241//! == fruit::Model {
242//! id: 1,
243//! name: "Apple".to_owned(),
244//! cake_id: None,
245//! };
246//! # Ok(())
247//! # }
248//!
249//! # async fn function_2(db: &DbConn) -> Result<(), DbErr> {
250//! # let apple = fruit::ActiveModel {
251//! # name: Set("Apple".to_owned()),
252//! # ..Default::default() // no need to set primary key
253//! # };
254//! # let pear = fruit::ActiveModel {
255//! # name: Set("Pear".to_owned()),
256//! # ..Default::default()
257//! # };
258//! // insert with ON CONFLICT on primary key do nothing, with MySQL specific polyfill
259//! let result = Fruit::insert_many([apple, pear])
260//! .on_conflict_do_nothing()
261//! .exec(db)
262//! .await?;
263//!
264//! matches!(result, TryInsertResult::Conflicted);
265//! # Ok(())
266//! # }
267//! ```
268//!
269//! ### Update
270//! ```
271//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
272//! use sea_orm::sea_query::{Expr, Value};
273//!
274//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
275//! let pear: Option<fruit::Model> = Fruit::find_by_id(1).one(db).await?;
276//! let mut pear: fruit::ActiveModel = pear.unwrap().into();
277//!
278//! pear.name = Set("Sweet pear".to_owned());
279//!
280//! // update one: only changed columns will be updated (not all columns)
281//! let pear: fruit::Model = pear.update(db).await?;
282//!
283//! // update many: UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."name" LIKE '%Apple%'
284//! Fruit::update_many()
285//! .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
286//! .filter(fruit::Column::Name.contains("Apple"))
287//! .exec(db)
288//! .await?;
289//!
290//! # Ok(())
291//! # }
292//! ```
293//! ### Save
294//! ```
295//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
296//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
297//! let banana = fruit::ActiveModel {
298//! id: NotSet,
299//! name: Set("Banana".to_owned()),
300//! ..Default::default()
301//! };
302//!
303//! // create, because primary key `id` is `NotSet`
304//! let mut banana = banana.save(db).await?;
305//!
306//! banana.name = Set("Banana Mongo".to_owned());
307//!
308//! // update, because primary key `id` is `Set`
309//! let banana = banana.save(db).await?;
310//!
311//! # Ok(())
312//! # }
313//! ```
314//! ### Delete
315//! ```
316//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
317//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
318//! // delete one
319//! let orange: Option<fruit::Model> = Fruit::find_by_id(1).one(db).await?;
320//! let orange: fruit::Model = orange.unwrap();
321//! fruit::Entity::delete(orange.into_active_model())
322//! .exec(db)
323//! .await?;
324//!
325//! // or simply
326//! let orange: Option<fruit::Model> = Fruit::find_by_id(1).one(db).await?;
327//! let orange: fruit::Model = orange.unwrap();
328//! orange.delete(db).await?;
329//!
330//! // delete many: DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Orange%'
331//! fruit::Entity::delete_many()
332//! .filter(fruit::Column::Name.contains("Orange"))
333//! .exec(db)
334//! .await?;
335//!
336//! # Ok(())
337//! # }
338//! ```
339//! ### Ergonomic Raw SQL
340//! The `raw_sql!` macro is like the `format!` macro but without the risk of SQL injection.
341//! It supports nested parameter interpolation, array and tuple expansion, and even repeating group,
342//! offering great flexibility in crafting complex queries.
343//!
344//! ```
345//! # use sea_orm::{DbConn, DbErr, query::*, FromQueryResult, raw_sql};
346//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
347//! #[derive(FromQueryResult)]
348//! struct Cake {
349//! name: String,
350//! #[sea_orm(nested)]
351//! bakery: Option<Bakery>,
352//! }
353//!
354//! #[derive(FromQueryResult)]
355//! struct Bakery {
356//! #[sea_orm(alias = "bakery_name")]
357//! name: String,
358//! }
359//!
360//! let cake_ids = [2, 3, 4]; // expanded by the `..` operator
361//!
362//! // can use many APIs with raw SQL, including nested select
363//! let cake: Option<Cake> = Cake::find_by_statement(raw_sql!(
364//! Sqlite,
365//! r#"SELECT "cake"."name", "bakery"."name" AS "bakery_name"
366//! FROM "cake"
367//! LEFT JOIN "bakery" ON "cake"."bakery_id" = "bakery"."id"
368//! WHERE "cake"."id" IN ({..cake_ids})"#
369//! ))
370//! .one(db)
371//! .await?;
372//! # Ok(())
373//! # }
374//! ```
375//!
376//! ## π§ Seaography: instant GraphQL API
377//!
378//! [Seaography](https://github.com/SeaQL/seaography) is a GraphQL framework built on top of SeaORM. Seaography allows you to build GraphQL resolvers quickly. With just a few commands, you can launch a GraphQL server from SeaORM entities!
379//!
380//! Look at the [Seaography Example](https://github.com/SeaQL/sea-orm/tree/master/examples/seaography_example) to learn more.
381//!
382//! <img src="https://raw.githubusercontent.com/SeaQL/sea-orm/master/examples/seaography_example/Seaography%20example.png"/>
383//!
384//! ## π₯οΈ SeaORM Pro: Professional Admin Panel
385//!
386//! [SeaORM Pro](https://www.sea-ql.org/sea-orm-pro/) is an admin panel solution allowing you to quickly and easily launch an admin panel for your application - frontend development skills not required, but certainly nice to have!
387//!
388//! Features:
389//!
390//! + Full CRUD
391//! + Built on React + GraphQL
392//! + Built-in GraphQL resolver
393//! + Customize the UI with simple TOML
394//!
395//! Learn More
396//!
397//! + [Example Repo](https://github.com/SeaQL/sea-orm-pro)
398//! + [Getting Started with Loco](https://www.sea-ql.org/sea-orm-pro/docs/install-and-config/getting-started-loco/)
399//! + [Getting Started with Axum](https://www.sea-ql.org/sea-orm-pro/docs/install-and-config/getting-started-axum/)
400//!
401//! 
402//! 
403//!
404//! ## Releases
405//!
406//! [SeaORM 1.0](https://www.sea-ql.org/blog/2024-08-04-sea-orm-1.0/) is a stable release. The 1.x version will be updated until at least October 2025, and we'll decide whether to release a 2.0 version or extend the 1.x life cycle.
407//!
408//! It doesn't mean that SeaORM is 'done', we've designed an architecture to allow us to deliver new features without major breaking changes. In fact, more features are coming!
409//!
410//! + [Change Log](https://github.com/SeaQL/sea-orm/tree/master/CHANGELOG.md)
411//!
412//! ### Who's using SeaORM?
413//!
414//! Here is a short list of awesome open source software built with SeaORM. [Full list here](https://github.com/SeaQL/sea-orm/blob/master/COMMUNITY.md#built-with-seaorm). Feel free to submit yours!
415//!
416//! | Project | GitHub | Tagline |
417//! |---------|--------|---------|
418//! | [Zed](https://github.com/zed-industries/zed) |  | A high-performance, multiplayer code editor |
419//! | [OpenObserve](https://github.com/openobserve/openobserve) |  | Open-source observability platform |
420//! | [RisingWave](https://github.com/risingwavelabs/risingwave) |  | Stream processing and management platform |
421//! | [LLDAP](https://github.com/nitnelave/lldap) |  | A light LDAP server for user management |
422//! | [Warpgate](https://github.com/warp-tech/warpgate) |  | Smart SSH bastion that works with any SSH client |
423//! | [Svix](https://github.com/svix/svix-webhooks) |  | The enterprise ready webhooks service |
424//! | [Ryot](https://github.com/IgnisDa/ryot) |  | The only self hosted tracker you will ever need |
425//! | [Lapdev](https://github.com/lapce/lapdev) |  | Self-hosted remote development enviroment |
426//! | [System Initiative](https://github.com/systeminit/si) |  | DevOps Automation Platform |
427//! | [OctoBase](https://github.com/toeverything/OctoBase) |  | A light-weight, scalable, offline collaborative data backend |
428//!
429//! ## License
430//!
431//! Licensed under either of
432//!
433//! - Apache License, Version 2.0
434//! ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
435//! - MIT license
436//! ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
437//!
438//! at your option.
439//!
440//! ## Contribution
441//!
442//! Unless you explicitly state otherwise, any contribution intentionally submitted
443//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
444//! dual licensed as above, without any additional terms or conditions.
445//!
446//! We invite you to participate, contribute and together help build Rust's future.
447//!
448//! A big shout out to our contributors!
449//!
450//! [](https://github.com/SeaQL/sea-orm/graphs/contributors)
451//!
452//! ## Sponsorship
453//!
454//! [SeaQL.org](https://www.sea-ql.org/) is an independent open-source organization run by passionate developers. If you enjoy using our libraries, please star and share our repositories. If you feel generous, a small donation via [GitHub Sponsor](https://github.com/sponsors/SeaQL) will be greatly appreciated, and goes a long way towards sustaining the organization.
455//!
456//! ### Gold Sponsors
457//!
458//! <table><tr>
459//! <td><a href="https://qdx.co/">
460//! <img src="https://www.sea-ql.org/static/sponsors/QDX.svg" width="138"/>
461//! </a></td>
462//! </tr></table>
463//!
464//! [QDX](https://qdx.co/) pioneers quantum dynamics-powered drug discovery, leveraging AI and supercomputing to accelerate molecular modeling.
465//! We're immensely grateful to QDX for sponsoring the development of SeaORM, the SQL toolkit that powers their data engineering workflows.
466//!
467//! ### Silver Sponsors
468//!
469//! Weβre grateful to our silver sponsors: Digital Ocean, for sponsoring our servers. And JetBrains, for sponsoring our IDE.
470//!
471//! <table><tr>
472//! <td><a href="https://www.digitalocean.com/">
473//! <img src="https://www.sea-ql.org/static/sponsors/DigitalOcean.svg" width="125">
474//! </a></td>
475//!
476//! <td><a href="https://www.jetbrains.com/">
477//! <img src="https://www.sea-ql.org/static/sponsors/JetBrains.svg" width="125">
478//! </a></td>
479//! </tr></table>
480//!
481//! ## Mascot
482//!
483//! A friend of Ferris, Terres the hermit crab is the official mascot of SeaORM. His hobby is collecting shells.
484//!
485//! <img alt="Terres" src="https://www.sea-ql.org/SeaORM/img/Terres.png" width="400"/>
486//!
487//! ### Rustacean Sticker Pack π¦
488//!
489//! The Rustacean Sticker Pack is the perfect way to express your passion for Rust.
490//! Our stickers are made with a premium water-resistant vinyl with a unique matte finish.
491//! Stick them on your laptop, notebook, or any gadget to show off your love for Rust!
492//!
493//! Sticker Pack Contents:
494//! - Logo of SeaQL projects: SeaQL, SeaORM, SeaQuery, Seaography, FireDBG
495//! - Mascot of SeaQL: Terres the Hermit Crab
496//! - Mascot of Rust: Ferris the Crab
497//! - The Rustacean word
498//!
499//! [Support SeaQL and get a Sticker Pack!](https://www.sea-ql.org/sticker-pack/) All proceeds contributes directly to the ongoing development of SeaQL projects.
500//!
501//! <a href="https://www.sea-ql.org/sticker-pack/"><img alt="Rustacean Sticker Pack by SeaQL" src="https://www.sea-ql.org/static/sticker-pack-1s.jpg" width="600"/></a>
502#![doc(
503 html_logo_url = "https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQL icon dark.png"
504)]
505
506mod database;
507mod docs;
508mod driver;
509/// Module for the Entity type and operations
510pub mod entity;
511/// Error types for all database operations
512pub mod error;
513/// This module performs execution of queries on a Model or ActiveModel
514mod executor;
515/// Types and methods to perform metric collection
516pub mod metric;
517/// Types and methods to perform queries
518pub mod query;
519#[cfg(feature = "rbac")]
520pub mod rbac;
521/// Types that defines the schemas of an Entity
522pub mod schema;
523/// Helpers for working with Value
524pub mod value;
525
526#[doc(hidden)]
527#[cfg(all(feature = "macros", feature = "tests-cfg"))]
528pub mod tests_cfg;
529mod util;
530
531pub use database::*;
532#[allow(unused_imports)]
533pub use driver::*;
534pub use entity::*;
535pub use error::*;
536pub use executor::*;
537pub use query::*;
538pub use schema::*;
539
540#[cfg(feature = "macros")]
541pub use sea_orm_macros::{
542 DeriveActiveEnum, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveDisplay,
543 DeriveEntity, DeriveEntityModel, DeriveIden, DeriveIntoActiveModel, DeriveMigrationName,
544 DeriveModel, DerivePartialModel, DerivePrimaryKey, DeriveRelatedEntity, DeriveRelation,
545 DeriveValueType, FromJsonQueryResult, FromQueryResult, raw_sql,
546};
547
548pub use sea_query;
549pub use sea_query::Iden;
550
551pub use sea_orm_macros::EnumIter;
552pub use strum;
553
554#[cfg(feature = "sqlx-dep")]
555pub use sqlx;