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/1.1.x/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 2024](https://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](https://github.com/SeaQL/sea-orm/tree/master/examples/seaography_example)
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//! ```
137//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
138//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
139//! // find all models
140//! let cakes: Vec<cake::Model> = Cake::find().all(db).await?;
141//!
142//! // find and filter
143//! let chocolate: Vec<cake::Model> = Cake::find()
144//! .filter(cake::Column::Name.contains("chocolate"))
145//! .all(db)
146//! .await?;
147//!
148//! // find one model
149//! let cheese: Option<cake::Model> = Cake::find_by_id(1).one(db).await?;
150//! let cheese: cake::Model = cheese.unwrap();
151//!
152//! // find related models (lazy)
153//! let fruits: Vec<fruit::Model> = cheese.find_related(Fruit).all(db).await?;
154//!
155//! // find related models (eager)
156//! let cake_with_fruits: Vec<(cake::Model, Vec<fruit::Model>)> =
157//! Cake::find().find_with_related(Fruit).all(db).await?;
158//! # Ok(())
159//! # }
160//! ```
161//!
162//! ### Nested Select
163//!
164//! ```
165//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
166//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
167//! use sea_orm::DerivePartialModel;
168//!
169//! #[derive(DerivePartialModel)]
170//! #[sea_orm(entity = "cake::Entity")]
171//! struct CakeWithFruit {
172//! id: i32,
173//! name: String,
174//! #[sea_orm(nested)]
175//! fruit: Option<fruit::Model>,
176//! }
177//!
178//! let cakes: Vec<CakeWithFruit> = cake::Entity::find()
179//! .left_join(fruit::Entity)
180//! .into_partial_model()
181//! .all(db)
182//! .await?;
183//! # Ok(())
184//! # }
185//! ```
186//!
187//! ### Insert
188//! ```
189//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
190//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
191//! let apple = fruit::ActiveModel {
192//! name: Set("Apple".to_owned()),
193//! ..Default::default() // no need to set primary key
194//! };
195//!
196//! let pear = fruit::ActiveModel {
197//! name: Set("Pear".to_owned()),
198//! ..Default::default()
199//! };
200//!
201//! // insert one
202//! let pear = pear.insert(db).await?;
203//! # Ok(())
204//! # }
205//! # async fn function2(db: &DbConn) -> Result<(), DbErr> {
206//! # let apple = fruit::ActiveModel {
207//! # name: Set("Apple".to_owned()),
208//! # ..Default::default() // no need to set primary key
209//! # };
210//! # let pear = fruit::ActiveModel {
211//! # name: Set("Pear".to_owned()),
212//! # ..Default::default()
213//! # };
214//!
215//! // insert many returning last insert id
216//! let result = Fruit::insert_many([apple, pear]).exec(db).await?;
217//! result.last_insert_id == Some(2);
218//! # Ok(())
219//! # }
220//! ```
221//!
222//! ### Insert (advanced)
223//! ```
224//! # use sea_orm::{DbConn, TryInsertResult, error::*, entity::*, query::*, tests_cfg::*};
225//! # async fn function_1(db: &DbConn) -> Result<(), DbErr> {
226//! # let apple = fruit::ActiveModel {
227//! # name: Set("Apple".to_owned()),
228//! # ..Default::default() // no need to set primary key
229//! # };
230//! # let pear = fruit::ActiveModel {
231//! # name: Set("Pear".to_owned()),
232//! # ..Default::default()
233//! # };
234//! // insert many with returning (if supported by database)
235//! let models: Vec<fruit::Model> = Fruit::insert_many([apple, pear])
236//! .exec_with_returning(db)
237//! .await?;
238//! models[0]
239//! == fruit::Model {
240//! id: 1,
241//! name: "Apple".to_owned(),
242//! cake_id: None,
243//! };
244//! # Ok(())
245//! # }
246//!
247//! # async fn function_2(db: &DbConn) -> Result<(), DbErr> {
248//! # let apple = fruit::ActiveModel {
249//! # name: Set("Apple".to_owned()),
250//! # ..Default::default() // no need to set primary key
251//! # };
252//! # let pear = fruit::ActiveModel {
253//! # name: Set("Pear".to_owned()),
254//! # ..Default::default()
255//! # };
256//! // insert with ON CONFLICT on primary key do nothing, with MySQL specific polyfill
257//! let result = Fruit::insert_many([apple, pear])
258//! .on_conflict_do_nothing()
259//! .exec(db)
260//! .await?;
261//!
262//! matches!(result, TryInsertResult::Conflicted);
263//! # Ok(())
264//! # }
265//! ```
266//!
267//! ### Update
268//! ```
269//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
270//! use sea_orm::sea_query::{Expr, Value};
271//!
272//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
273//! let pear: Option<fruit::Model> = Fruit::find_by_id(1).one(db).await?;
274//! let mut pear: fruit::ActiveModel = pear.unwrap().into();
275//!
276//! pear.name = Set("Sweet pear".to_owned());
277//!
278//! // update one
279//! let pear: fruit::Model = pear.update(db).await?;
280//!
281//! // update many: UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."name" LIKE '%Apple%'
282//! Fruit::update_many()
283//! .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None)))
284//! .filter(fruit::Column::Name.contains("Apple"))
285//! .exec(db)
286//! .await?;
287//!
288//! # Ok(())
289//! # }
290//! ```
291//! ### Save
292//! ```
293//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
294//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
295//! let banana = fruit::ActiveModel {
296//! id: NotSet,
297//! name: Set("Banana".to_owned()),
298//! ..Default::default()
299//! };
300//!
301//! // create, because primary key `id` is `NotSet`
302//! let mut banana = banana.save(db).await?;
303//!
304//! banana.name = Set("Banana Mongo".to_owned());
305//!
306//! // update, because primary key `id` is `Set`
307//! let banana = banana.save(db).await?;
308//!
309//! # Ok(())
310//! # }
311//! ```
312//! ### Delete
313//! ```
314//! # use sea_orm::{DbConn, error::*, entity::*, query::*, tests_cfg::*};
315//! # async fn function(db: &DbConn) -> Result<(), DbErr> {
316//! // delete one
317//! let orange: Option<fruit::Model> = Fruit::find_by_id(1).one(db).await?;
318//! let orange: fruit::Model = orange.unwrap();
319//! fruit::Entity::delete(orange.into_active_model())
320//! .exec(db)
321//! .await?;
322//!
323//! // or simply
324//! let orange: Option<fruit::Model> = Fruit::find_by_id(1).one(db).await?;
325//! let orange: fruit::Model = orange.unwrap();
326//! orange.delete(db).await?;
327//!
328//! // delete many: DELETE FROM "fruit" WHERE "fruit"."name" LIKE 'Orange'
329//! fruit::Entity::delete_many()
330//! .filter(fruit::Column::Name.contains("Orange"))
331//! .exec(db)
332//! .await?;
333//!
334//! # Ok(())
335//! # }
336//! ```
337//!
338//! ## π§ Seaography: instant GraphQL API
339//!
340//! [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!
341//!
342//! Look at the [Seaography Example](https://github.com/SeaQL/sea-orm/tree/master/examples/seaography_example) to learn more.
343//!
344//! <img src="https://raw.githubusercontent.com/SeaQL/sea-orm/master/examples/seaography_example/Seaography%20example.png"/>
345//!
346//! ## π₯οΈ SeaORM Pro: Professional Admin Panel
347//!
348//! [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!
349//!
350//! Features:
351//!
352//! + Full CRUD
353//! + Built on React + GraphQL
354//! + Built-in GraphQL resolver
355//! + Customize the UI with simple TOML
356//!
357//! Learn More
358//!
359//! + [Example Repo](https://github.com/SeaQL/sea-orm-pro)
360//! + [Getting Started with Loco](https://www.sea-ql.org/sea-orm-pro/docs/install-and-config/getting-started-loco/)
361//! + [Getting Started with Axum](https://www.sea-ql.org/sea-orm-pro/docs/install-and-config/getting-started-axum/)
362//!
363//! 
364//! 
365//!
366//! ## Releases
367//!
368//! [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.
369//!
370//! 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!
371//!
372//! + [Change Log](https://github.com/SeaQL/sea-orm/tree/master/CHANGELOG.md)
373//!
374//! ### Who's using SeaORM?
375//!
376//! 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!
377//!
378//! | Project | GitHub | Tagline |
379//! |---------|--------|---------|
380//! | [Zed](https://github.com/zed-industries/zed) |  | A high-performance, multiplayer code editor |
381//! | [OpenObserve](https://github.com/openobserve/openobserve) |  | Open-source observability platform |
382//! | [RisingWave](https://github.com/risingwavelabs/risingwave) |  | Stream processing and management platform |
383//! | [LLDAP](https://github.com/nitnelave/lldap) |  | A light LDAP server for user management |
384//! | [Warpgate](https://github.com/warp-tech/warpgate) |  | Smart SSH bastion that works with any SSH client |
385//! | [Svix](https://github.com/svix/svix-webhooks) |  | The enterprise ready webhooks service |
386//! | [Ryot](https://github.com/IgnisDa/ryot) |  | The only self hosted tracker you will ever need |
387//! | [Lapdev](https://github.com/lapce/lapdev) |  | Self-hosted remote development enviroment |
388//! | [System Initiative](https://github.com/systeminit/si) |  | DevOps Automation Platform |
389//! | [OctoBase](https://github.com/toeverything/OctoBase) |  | A light-weight, scalable, offline collaborative data backend |
390//!
391//! ## License
392//!
393//! Licensed under either of
394//!
395//! - Apache License, Version 2.0
396//! ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
397//! - MIT license
398//! ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
399//!
400//! at your option.
401//!
402//! ## Contribution
403//!
404//! Unless you explicitly state otherwise, any contribution intentionally submitted
405//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
406//! dual licensed as above, without any additional terms or conditions.
407//!
408//! We invite you to participate, contribute and together help build Rust's future.
409//!
410//! A big shout out to our contributors!
411//!
412//! [](https://github.com/SeaQL/sea-orm/graphs/contributors)
413//!
414//! ## Sponsorship
415//!
416//! [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.
417//!
418//! ### Gold Sponsors
419//!
420//! <table><tr>
421//! <td><a href="https://qdx.co/">
422//! <img src="https://www.sea-ql.org/static/sponsors/QDX.svg" width="138"/>
423//! </a></td>
424//! </tr></table>
425//!
426//! [QDX](https://qdx.co/) pioneers quantum dynamics-powered drug discovery, leveraging AI and supercomputing to accelerate molecular modeling.
427//! We're immensely grateful to QDX for sponsoring the development of SeaORM, the SQL toolkit that powers their data engineering workflows.
428//!
429//! ### Silver Sponsors
430//!
431//! Weβre grateful to our silver sponsors: Digital Ocean, for sponsoring our servers. And JetBrains, for sponsoring our IDE.
432//!
433//! <table><tr>
434//! <td><a href="https://www.digitalocean.com/">
435//! <img src="https://www.sea-ql.org/static/sponsors/DigitalOcean.svg" width="125">
436//! </a></td>
437//!
438//! <td><a href="https://www.jetbrains.com/">
439//! <img src="https://www.sea-ql.org/static/sponsors/JetBrains.svg" width="125">
440//! </a></td>
441//! </tr></table>
442//!
443//! ## Mascot
444//!
445//! A friend of Ferris, Terres the hermit crab is the official mascot of SeaORM. His hobby is collecting shells.
446//!
447//! <img alt="Terres" src="https://www.sea-ql.org/SeaORM/img/Terres.png" width="400"/>
448//!
449//! ### Rustacean Sticker Pack π¦
450//!
451//! The Rustacean Sticker Pack is the perfect way to express your passion for Rust.
452//! Our stickers are made with a premium water-resistant vinyl with a unique matte finish.
453//! Stick them on your laptop, notebook, or any gadget to show off your love for Rust!
454//!
455//! Sticker Pack Contents:
456//! - Logo of SeaQL projects: SeaQL, SeaORM, SeaQuery, Seaography, FireDBG
457//! - Mascot of SeaQL: Terres the Hermit Crab
458//! - Mascot of Rust: Ferris the Crab
459//! - The Rustacean word
460//!
461//! [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.
462//!
463//! <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>
464#![doc(
465 html_logo_url = "https://raw.githubusercontent.com/SeaQL/sea-query/master/docs/SeaQL icon dark.png"
466)]
467
468mod database;
469mod docs;
470mod driver;
471/// Module for the Entity type and operations
472pub mod entity;
473/// Error types for all database operations
474pub mod error;
475/// This module performs execution of queries on a Model or ActiveModel
476mod executor;
477/// Types and methods to perform metric collection
478pub mod metric;
479/// Types and methods to perform queries
480pub mod query;
481#[cfg(feature = "rbac")]
482pub mod rbac;
483/// Types that defines the schemas of an Entity
484pub mod schema;
485/// Helpers for working with Value
486pub mod value;
487
488#[doc(hidden)]
489#[cfg(all(feature = "macros", feature = "tests-cfg"))]
490pub mod tests_cfg;
491mod util;
492
493pub use database::*;
494#[allow(unused_imports)]
495pub use driver::*;
496pub use entity::*;
497pub use error::*;
498pub use executor::*;
499pub use query::*;
500pub use schema::*;
501
502#[cfg(feature = "macros")]
503pub use sea_orm_macros::{
504 DeriveActiveEnum, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveDisplay,
505 DeriveEntity, DeriveEntityModel, DeriveIden, DeriveIntoActiveModel, DeriveMigrationName,
506 DeriveModel, DerivePartialModel, DerivePrimaryKey, DeriveRelatedEntity, DeriveRelation,
507 DeriveValueType, FromJsonQueryResult, FromQueryResult,
508};
509
510pub use sea_query;
511pub use sea_query::Iden;
512
513pub use sea_orm_macros::EnumIter;
514pub use strum;
515
516#[cfg(feature = "sqlx-dep")]
517pub use sqlx;