diff --git a/SeaORM/blog/2021-11-19-whats-new-in-0.4.0.md b/SeaORM/blog/2021-11-19-whats-new-in-0.4.0.md new file mode 100644 index 00000000000..e55c4d61abc --- /dev/null +++ b/SeaORM/blog/2021-11-19-whats-new-in-0.4.0.md @@ -0,0 +1,304 @@ +--- +slug: 2021-11-19-whats-new-in-0.4.0 +title: What's new in SeaORM 0.4.0 +author: SeaQL Team +author_title: Chris Tsang +author_url: https://github.com/SeaQL +author_image_url: https://www.sea-ql.org/SeaORM/img/SeaQL.png +tags: [news] +--- + +🎉 We are pleased to release SeaORM [`0.4.0`](https://github.com/SeaQL/sea-orm/releases/tag/0.4.0) today! Here are some feature highlights 🌟: + +## ActiveEnum + +[[#258](https://github.com/SeaQL/sea-orm/pull/258)] You can now use custom enum in model where each enum variants are serialized into database value of string, integer or native database enum. Please find [here](/SeaORM/docs/basic-crud/active-enum) for the in-depth documentation. + +```rust +#[derive(Debug, Clone, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "active_enum")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + // Use our custom enum in a model + pub category: Option, + pub color: Option, + pub tea: Option, +} + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "String(Some(1))")] +// An enum serialized into database as a string value +pub enum Category { + #[sea_orm(string_value = "B")] + Big, + #[sea_orm(string_value = "S")] + Small, +} + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "i32", db_type = "Integer")] +// An enum serialized into database as an integer value +pub enum Color { + #[sea_orm(num_value = 0)] + Black, + #[sea_orm(num_value = 1)] + White, +} + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] +// An enum serialized into database as a database native enum +pub enum Tea { + #[sea_orm(string_value = "EverydayTea")] + EverydayTea, + #[sea_orm(string_value = "BreakfastTea")] + BreakfastTea, +} + +#[derive(Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} +``` + +Contributed by: + +
+
+
+ + + +
+
+ Billy Chan +
+
+
+
+
+ +## Supports RETURNING Clause on PostgreSQL + +[[#292](https://github.com/SeaQL/sea-orm/pull/292)] When performing insert or update operation on `ActiveModel` against PostgreSQL, RETURNING clause will be used to avoid excessive querying of inserted or updated model from the database. + +```rust +// For PostgreSQL +cake::ActiveModel { + name: Set("Apple Pie".to_owned()), + ..Default::default() +} +.insert(&postgres_db) +.await?; + +assert_eq!( + postgres_db.into_transaction_log(), + vec![Transaction::from_sql_and_values( + DbBackend::Postgres, + r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id", "name""#, + vec!["Apple Pie".into()] + )]); +``` + +```rust +// For MySQL & SQLite +cake::ActiveModel { + name: Set("Apple Pie".to_owned()), + ..Default::default() +} +.insert(&other_db) +.await?; + +assert_eq!( + other_db.into_transaction_log(), + vec![ + Transaction::from_sql_and_values( + DbBackend::MySql, + r#"INSERT INTO `cake` (`name`) VALUES (?)"#, + vec!["Apple Pie".into()] + ), + Transaction::from_sql_and_values( + DbBackend::MySql, + r#"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = ? LIMIT ?"#, + vec![15.into(), 1u64.into()] + )]); +``` + +Contributed by: + +
+
+
+ + + +
+
+ Billy Chan +
+
+
+
+
+
+ + + +
+
+ Marlon Brandão de Sousa +
+
+
+
+
+ +## Axum Integration Example + +[[#297](https://github.com/SeaQL/sea-orm/pull/297)] Introducing [Axum integration example](https://github.com/SeaQL/sea-orm/tree/master/examples/axum_example) which is Axum version of [Actix4](https://github.com/SeaQL/sea-orm/tree/master/examples/actix4_example) and [Actix3](https://github.com/SeaQL/sea-orm/tree/master/examples/actix_example) integration examples. + +Contributed by: + +
+
+
+ + + +
+
+ Yoshiera +
+
+
+
+
+ +## Rust Edition 2021 + +[[#273](https://github.com/SeaQL/sea-orm/pull/273)] Updating all SeaORM crates to [Rust Edition 2021](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html#rust-2021) + +Contributed by: + +
+
+
+ + + +
+
+ Carter Snook +
+
+
+
+
+ +## PaginatorTrait + +[[#306](https://github.com/SeaQL/sea-orm/pull/306)] Refactor `paginate()` & `count()` utilities into `PaginatorTrait`. You can use the paginator as usual but you might need to import `PaginatorTrait` manually when upgrading to `0.4.x`. + +```rust +use futures::TryStreamExt; +use sea_orm::{entity::*, query::*, tests_cfg::cake}; + +let mut cake_stream = cake::Entity::find() + .order_by_asc(cake::Column::Id) + .paginate(db, 50) + .into_stream(); + +while let Some(cakes) = cake_stream.try_next().await? { + // Do something on cakes: Vec +} +``` + +Contributed by: + +
+
+
+ + + +
+
+ Yoshiera +
+
+
+
+
+ +## Database Specific Schema Helper + +[[#309](https://github.com/SeaQL/sea-orm/pull/309)] The helper struct `Schema` converting `EntityTrait` into different `sea-query` statement now has to be initialized with `DbBackend`. + +```rust +use sea_orm::{tests_cfg::*, DbBackend, Schema}; +use sea_orm::sea_query::TableCreateStatement; + +// Before `0.4.x` +let _: TableCreateStatement = Schema::create_table_from_entity(cake::Entity); + +// Now +let schema: Schema = Schema::new(DbBackend::MySql); +let _: TableCreateStatement = schema.create_table_from_entity(cake::Entity); +``` + +Contributed by: + +
+
+
+ + + +
+
+ Billy Chan +
+
+
+
+
+ +## Disable SQLx Logging + +[[#290](https://github.com/SeaQL/sea-orm/pull/290)] You can now disable SQLx statement logging when initializing the connection. + +```rust +let mut opt = ConnectOptions::new("protocol://username:password@host/database".to_owned()); +opt.max_connections(100) + .min_connections(5) + .connect_timeout(Duration::from_secs(8)) + .idle_timeout(Duration::from_secs(8)) + // Disable SQLx statement logging + .sqlx_logging(false); + +let db = Database::connect(opt).await?; +``` + +Contributed by: + +
+
+
+ + + +
+
+ Chris Tsang +
+
+
+
+
+ +## Community + +SeaQL is a community driven project. We welcome you to participate, contribute and together build for Rust's future. + +Here is the roadmap for SeaORM [`0.5.x`](https://github.com/SeaQL/sea-orm/milestone/5). \ No newline at end of file diff --git a/SeaORM/docs/01-index.md b/SeaORM/docs/01-index.md index 2e937e1c548..3b89fd1fc8c 100644 --- a/SeaORM/docs/01-index.md +++ b/SeaORM/docs/01-index.md @@ -28,64 +28,76 @@ 2.3 [Expanded Entity Structure](/docs/generate-entity/expanded-entity-structure) -3. Basic CRUD +3. Generating Database Schema - 3.1 [SELECT: find, filter, sort, paging](/docs/basic-crud/select) + 3.1 [Create Table](/docs/generate-database-schema/create-table) - 3.2 [INSERT: Model & ActiveModel, insert many](/docs/basic-crud/insert) + 3.2 [Create Enum](/docs/generate-database-schema/create-enum) - 3.3 [UPDATE: find & save, update many](/docs/basic-crud/update) +4. Basic CRUD - 3.4 [SAVE: insert or update](/docs/basic-crud/save) + 4.1 [SELECT: find, filter, sort, paging](/docs/basic-crud/select) - 3.5 [DELETE: delete one & delete many](/docs/basic-crud/delete) + 4.2 [INSERT: Model & ActiveModel, insert many](/docs/basic-crud/insert) - 3.6 [JSON](/docs/basic-crud/json) + 4.3 [UPDATE: find & save, update many](/docs/basic-crud/update) - 3.7 [Raw SQL query](/docs/basic-crud/raw-sql) + 4.4 [SAVE: insert or update](/docs/basic-crud/save) + + 4.5 [DELETE: delete one & delete many](/docs/basic-crud/delete) + + 4.6 [JSON](/docs/basic-crud/json) + + 4.7 [Raw SQL query](/docs/basic-crud/raw-sql) + + 4.8 [ActiveEnum](/docs/basic-crud/active-enum) ## Learn More -4. Relations +5. Relations + + 5.1 [One to One](/docs/relation/one-to-one) + + 5.2 [One to Many](/docs/relation/one-to-many) - 4.1 [One to One](/docs/relation/one-to-one) + 5.3 [Many to Many](/docs/relation/many-to-many) - 4.2 [One to Many](/docs/relation/one-to-many) + 5.4 [Multiple Join Paths Between Two Entities](/docs/relation/multiple-join-paths-between-two-entities) - 4.3 [Many to Many](/docs/relation/many-to-many) + 5.5 [Self Referencing](/docs/relation/self-referencing) - 4.4 [Bakery Schema](/docs/relation/bakery-schema) + 5.6 [Bakery Schema](/docs/relation/bakery-schema) -5. Writing Tests +6. Writing Tests - 5.1 [Robust & Correct](/docs/write-test/testing) + 6.1 [Robust & Correct](/docs/write-test/testing) - 5.2 [Mock Interface](/docs/write-test/mock) + 6.2 [Mock Interface](/docs/write-test/mock) - 5.3 [Using SQLite](/docs/write-test/sqlite) + 6.3 [Using SQLite](/docs/write-test/sqlite) -6. Advanced Queries +7. Advanced Queries - 6.1 [Custom select](/docs/advanced-query/custom-select) + 7.1 [Custom select](/docs/advanced-query/custom-select) - 6.2 [Conditional expressions](/docs/advanced-query/conditional-expression) + 7.2 [Conditional expressions](/docs/advanced-query/conditional-expression) - 6.3 [Aggregate functions](/docs/advanced-query/aggregate-function) + 7.3 [Aggregate functions](/docs/advanced-query/aggregate-function) - 6.4 [Advanced Relations](/docs/advanced-query/advanced-relations) + 7.4 [Advanced Relations](/docs/advanced-query/advanced-relations) - 6.5 [Subquery](/docs/advanced-query/subquery) + 7.5 [Subquery](/docs/advanced-query/subquery) - 6.6 [Transaction](/docs/advanced-query/transaction) + 7.6 [Transaction](/docs/advanced-query/transaction) - 6.7 [Streaming](/docs/advanced-query/streaming) + 7.7 [Streaming](/docs/advanced-query/streaming) - 6.8 [Custom Active Model](/docs/advanced-query/custom-active-model) + 7.8 [Custom Active Model](/docs/advanced-query/custom-active-model) -7. Internal Design +8. Internal Design - 7.1 [Traits and Types](/docs/internal-design/trait-and-type) + 8.1 [Traits and Types](/docs/internal-design/trait-and-type) - 7.2 [Derive Macros](/docs/internal-design/derive-macro) + 8.2 [Derive Macros](/docs/internal-design/derive-macro) - 7.3 [Compare with Diesel](/docs/internal-design/diesel) \ No newline at end of file + 8.3 [Compare with Diesel](/docs/internal-design/diesel) \ No newline at end of file diff --git a/SeaORM/docs/02-install-and-config/03-connection.md b/SeaORM/docs/02-install-and-config/03-connection.md index 9b2b9228863..04adbcba578 100644 --- a/SeaORM/docs/02-install-and-config/03-connection.md +++ b/SeaORM/docs/02-install-and-config/03-connection.md @@ -25,7 +25,8 @@ let mut opt = ConnectOptions::new("protocol://username:password@host/database".t opt.max_connections(100) .min_connections(5) .connect_timeout(Duration::from_secs(8)) - .idle_timeout(Duration::from_secs(8)); + .idle_timeout(Duration::from_secs(8)) + .sqlx_logging(true); let db = Database::connect(opt).await?; ``` diff --git a/SeaORM/docs/04-generate-database-schema/01-create-table.md b/SeaORM/docs/04-generate-database-schema/01-create-table.md new file mode 100644 index 00000000000..563577b4ab8 --- /dev/null +++ b/SeaORM/docs/04-generate-database-schema/01-create-table.md @@ -0,0 +1,130 @@ +# Create Table + +To create tables in database instead of writing [`TableCreateStatement`](https://docs.rs/sea-query/*/sea_query/table/struct.TableCreateStatement.html) manually, you can derive it from `Entity` using [`Schema::create_table_from_entity`](https://docs.rs/sea-orm/0.*/sea_orm/schema/struct.Schema.html#method.create_table_from_entity). This method will help you create database table including all columns and foreign key constraints defined in `Entity`. + +Below we use [`CakeFillingPrice`](https://github.com/SeaQL/sea-orm/blob/master/src/tests_cfg/cake_filling_price.rs) entity to demo its generated SQL statement. You can construct the same statement with [`TableCreateStatement`](https://docs.rs/sea-query/*/sea_query/table/struct.TableCreateStatement.html). + +```rust +use sea_orm::{sea_query::*, tests_cfg::*, EntityName, Schema}; + +let builder = db.get_database_backend(); +let schema = Schema::new(builder); + +assert_eq!( + builder.build(&schema.create_table_from_entity(CakeFillingPrice)), + builder.build( + &Table::create() + .table(CakeFillingPrice.table_ref()) + .col( + ColumnDef::new(cake_filling_price::Column::CakeId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(cake_filling_price::Column::FillingId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(cake_filling_price::Column::Price) + .decimal() + .not_null(), + ) + .primary_key( + Index::create() + .name("pk-cake_filling_price") + .col(cake_filling_price::Column::CakeId) + .col(cake_filling_price::Column::FillingId) + .primary(), + ) + .foreign_key( + ForeignKeyCreateStatement::new() + .name("fk-cake_filling_price-cake_filling") + .from_tbl(CakeFillingPrice) + .from_col(cake_filling_price::Column::CakeId) + .from_col(cake_filling_price::Column::FillingId) + .to_tbl(CakeFilling) + .to_col(cake_filling::Column::CakeId) + .to_col(cake_filling::Column::FillingId), + ) + .to_owned() + ) +); +``` + +To further illustrate it, we will show the SQL statement as string below. + +- PostgreSQL + ```rust + use sea_orm::{tests_cfg::*, DbBackend, Schema, Statement}; + + let db_postgres = DbBackend::Postgres; + let schema = Schema::new(db_postgres); + + assert_eq!( + db_postgres.build(&schema.create_table_from_entity(CakeFillingPrice)), + Statement::from_string( + db_postgres, + vec![ + r#"CREATE TABLE "public"."cake_filling_price" ("#, + r#""cake_id" integer NOT NULL,"#, + r#""filling_id" integer NOT NULL,"#, + r#""price" decimal NOT NULL,"#, + r#"CONSTRAINT "pk-cake_filling_price" PRIMARY KEY ("cake_id", "filling_id"),"#, + r#"CONSTRAINT "fk-cake_filling_price-cake_filling" FOREIGN KEY ("cake_id", "filling_id") REFERENCES "cake_filling" ("cake_id", "filling_id")"#, + r#")"#, + ] + .join(" ") + ) + ); + ``` + +- MySQL + ```rust + use sea_orm::{tests_cfg::*, DbBackend, Schema, Statement}; + + let db_mysql = DbBackend::MySql; + let schema = Schema::new(db_mysql); + + assert_eq!( + db_mysql.build(&schema.create_table_from_entity(CakeFillingPrice)), + Statement::from_string( + db_mysql, + vec![ + "CREATE TABLE `cake_filling_price` (", + "`cake_id` int NOT NULL,", + "`filling_id` int NOT NULL,", + "`price` decimal NOT NULL,", + "PRIMARY KEY `pk-cake_filling_price` (`cake_id`, `filling_id`),", + "CONSTRAINT `fk-cake_filling_price-cake_filling` FOREIGN KEY (`cake_id`, `filling_id`) REFERENCES `cake_filling` (`cake_id`, `filling_id`)", + ")", + ] + .join(" ") + ) + ); + ``` + +- SQLite + ```rust + use sea_orm::{tests_cfg::*, DbBackend, Schema, Statement}; + + let db_sqlite = DbBackend::Sqlite; + let schema = Schema::new(db_sqlite); + + assert_eq!( + db_sqlite.build(&schema.create_table_from_entity(CakeFillingPrice)), + Statement::from_string( + db_sqlite, + vec![ + "CREATE TABLE `cake_filling_price` (", + "`cake_id` integer NOT NULL,", + "`filling_id` integer NOT NULL,", + "`price` real NOT NULL,", + "CONSTRAINT `pk-cake_filling_price`PRIMARY KEY (`cake_id`, `filling_id`),", + "FOREIGN KEY (`cake_id`, `filling_id`) REFERENCES `cake_filling` (`cake_id`, `filling_id`)", + ")", + ] + .join(" ") + ) + ); + ``` diff --git a/SeaORM/docs/04-generate-database-schema/02-create-enum.md b/SeaORM/docs/04-generate-database-schema/02-create-enum.md new file mode 100644 index 00000000000..1ce06a178e2 --- /dev/null +++ b/SeaORM/docs/04-generate-database-schema/02-create-enum.md @@ -0,0 +1,195 @@ +# Create Enum + +After you have defined `Entity`, you can generate SQL statement to create database table with enum columns via the [`Schema`](https://docs.rs/sea-orm/0.*/sea_orm/schema/struct.Schema.html) helper struct. + +## String & Integer Enum + +As this is just an ordinary string / integer column in database table, you can use the [`Schema::create_table_from_entity`](https://docs.rs/sea-orm/0.*/sea_orm/schema/struct.Schema.html#method.create_table_from_entity) method like below. + +Defining the `Entity` and enums. + +```rust +pub mod active_enum { + use sea_orm::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] + #[sea_orm(schema_name = "public", table_name = "active_enum")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub category: Option, + pub color: Option, + } + + #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] + #[sea_orm(rs_type = "String", db_type = "String(Some(1))")] + pub enum Category { + #[sea_orm(string_value = "B")] + Big, + #[sea_orm(string_value = "S")] + Small, + } + + #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] + #[sea_orm(rs_type = "i32", db_type = "Integer")] + pub enum Color { + #[sea_orm(num_value = 0)] + Black, + #[sea_orm(num_value = 1)] + White, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} +} +``` + +Generating [`TableCreateStatement`](https://docs.rs/sea-query/*/sea_query/table/struct.TableCreateStatement.html) from `Entity`. + +```rust +use sea_orm::{sea_query, Schema}; + +let builder = db.get_database_backend(); +let schema = Schema::new(builder); + +assert_eq!( + builder.build(&schema.create_table_from_entity(active_enum::Entity)), + builder.build( + &sea_query::Table::create() + .table(active_enum::Entity.table_ref()) + .col( + sea_query::ColumnDef::new(active_enum::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(sea_query::ColumnDef::new(active_enum::Column::Category).string_len(1)) + .col(sea_query::ColumnDef::new(active_enum::Column::Color).integer()) + .to_owned() + ) +); +``` + +## Native Database Enum + +The enum support are different across databases. We will explain the creation of native database enum for each databases. + +Defining the `Entity` and enums. + +```rust +pub mod active_enum { + use sea_orm::entity::prelude::*; + + #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] + #[sea_orm(schema_name = "public", table_name = "active_enum")] + pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub tea: Option, + } + + #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] + #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] + pub enum Tea { + #[sea_orm(string_value = "EverydayTea")] + EverydayTea, + #[sea_orm(string_value = "BreakfastTea")] + BreakfastTea, + } + + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation {} + + impl ActiveModelBehavior for ActiveModel {} +} +``` + +### PostgreSQL + +Enum in PostgreSQL is defined as a custom type, it can be created with [`Schema::create_enum_from_entity`](https://docs.rs/sea-orm/0.*/sea_orm/schema/struct.Schema.html#method.create_enum_from_entity) method. + +```rust +use sea_orm::{Schema, Statement}; + +let db_postgres = DbBackend::Postgres; +let schema = Schema::new(db_postgres); + +assert_eq!( + schema + .create_enum_from_entity(active_enum::Entity) + .iter() + .map(|stmt| db_postgres.build(stmt)) + .collect::>(), + vec![Statement::from_string( + db_postgres, + r#"CREATE TYPE "tea" AS ENUM ('EverydayTea', 'BreakfastTea')"#.to_owned() + ),] +); + +assert_eq!( + db_postgres.build(&schema.create_table_from_entity(active_enum::Entity)), + Statement::from_string( + db_postgres, + vec![ + r#"CREATE TABLE "public"."active_enum" ("#, + r#""id" serial NOT NULL PRIMARY KEY,"#, + r#""tea" tea"#, + r#")"#, + ] + .join(" ") + ), +); +``` + +### MySQL + +In MySQL, enum is defined on table creation so you only need the [`Schema::create_table_from_entity`](https://docs.rs/sea-orm/0.*/sea_orm/schema/struct.Schema.html#method.create_table_from_entity) method. + +```rust +use sea_orm::{Schema, Statement}; + +let db_mysql = DbBackend::MySql; +let schema = Schema::new(db_mysql); + +assert_eq!( + db_mysql.build(&schema.create_table_from_entity(active_enum::Entity)), + Statement::from_string( + db_mysql, + vec![ + "CREATE TABLE `active_enum` (", + "`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,", + "`tea` ENUM('EverydayTea', 'BreakfastTea')", + ")", + ] + .join(" ") + ), +); +``` + +### SQLite + +Enum is not supported in SQLite so it will be stored as `TEXT` type. + +```rust +use sea_orm::{Schema, Statement}; + +let db_sqlite = DbBackend::Sqlite; +let schema = Schema::new(db_sqlite); + +assert_eq!( + db_sqlite.build(&schema.create_table_from_entity(active_enum::Entity)), + Statement::from_string( + db_sqlite, + vec![ + "CREATE TABLE `active_enum` (", + "`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,", + "`tea` text", + ")", + ] + .join(" ") + ), +); +``` diff --git a/SeaORM/docs/04-generate-database-schema/_category_.json b/SeaORM/docs/04-generate-database-schema/_category_.json new file mode 100644 index 00000000000..826ff2f328a --- /dev/null +++ b/SeaORM/docs/04-generate-database-schema/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Generating Database Schema", + "collapsed": false +} diff --git a/SeaORM/docs/04-basic-crud/01-select.md b/SeaORM/docs/05-basic-crud/01-select.md similarity index 100% rename from SeaORM/docs/04-basic-crud/01-select.md rename to SeaORM/docs/05-basic-crud/01-select.md diff --git a/SeaORM/docs/04-basic-crud/02-insert.md b/SeaORM/docs/05-basic-crud/02-insert.md similarity index 100% rename from SeaORM/docs/04-basic-crud/02-insert.md rename to SeaORM/docs/05-basic-crud/02-insert.md diff --git a/SeaORM/docs/04-basic-crud/03-update.md b/SeaORM/docs/05-basic-crud/03-update.md similarity index 100% rename from SeaORM/docs/04-basic-crud/03-update.md rename to SeaORM/docs/05-basic-crud/03-update.md diff --git a/SeaORM/docs/04-basic-crud/04-save.md b/SeaORM/docs/05-basic-crud/04-save.md similarity index 100% rename from SeaORM/docs/04-basic-crud/04-save.md rename to SeaORM/docs/05-basic-crud/04-save.md diff --git a/SeaORM/docs/04-basic-crud/05-delete.md b/SeaORM/docs/05-basic-crud/05-delete.md similarity index 100% rename from SeaORM/docs/04-basic-crud/05-delete.md rename to SeaORM/docs/05-basic-crud/05-delete.md diff --git a/SeaORM/docs/04-basic-crud/06-json.md b/SeaORM/docs/05-basic-crud/06-json.md similarity index 100% rename from SeaORM/docs/04-basic-crud/06-json.md rename to SeaORM/docs/05-basic-crud/06-json.md diff --git a/SeaORM/docs/04-basic-crud/07-raw-sql.md b/SeaORM/docs/05-basic-crud/07-raw-sql.md similarity index 100% rename from SeaORM/docs/04-basic-crud/07-raw-sql.md rename to SeaORM/docs/05-basic-crud/07-raw-sql.md diff --git a/SeaORM/docs/05-basic-crud/08-active-enum.md b/SeaORM/docs/05-basic-crud/08-active-enum.md new file mode 100644 index 00000000000..4f47ec4bce9 --- /dev/null +++ b/SeaORM/docs/05-basic-crud/08-active-enum.md @@ -0,0 +1,145 @@ +# ActiveEnum + +You can now use custom enum in model where each enum variants are serialized into database value of string, integer or native database enum. + +- String + ```rust + #[derive(EnumIter, DeriveActiveEnum)] + #[sea_orm(rs_type = "String", db_type = "String(Some(1))")] + pub enum Category { + #[sea_orm(string_value = "B")] + Big, + #[sea_orm(string_value = "S")] + Small, + } + ``` + +- Integer + ```rust + #[derive(EnumIter, DeriveActiveEnum)] + #[sea_orm(rs_type = "i32", db_type = "Integer")] + pub enum Color { + #[sea_orm(num_value = 0)] + Black, + #[sea_orm(num_value = 1)] + White, + } + ``` + +- Native Database Enum + ```rust + #[derive(EnumIter, DeriveActiveEnum)] + #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] + pub enum Tea { + #[sea_orm(string_value = "EverydayTea")] + EverydayTea, + #[sea_orm(string_value = "BreakfastTea")] + BreakfastTea, + } + ``` + +## Implementations + +You can implement [`ActiveEnum`](https://docs.rs/sea-orm/0.*/sea_orm/entity/trait.ActiveEnum.html) manually by hand or use the derive macro [`DeriveActiveEnum`](https://docs.rs/sea-orm/0.*/sea_orm/derive.DeriveActiveEnum.html). + +### Derive Implementation + +See [`DeriveActiveEnum`](https://docs.rs/sea-orm/0.*/sea_orm/derive.DeriveActiveEnum.html) for the full specification of macro attributes. + +```rust +use sea_orm::entity::prelude::*; + +// Using the derive macro +#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm( + rs_type = "String", + db_type = "String(Some(1))", + enum_name = "category" +)] +pub enum Category { + #[sea_orm(string_value = "B")] + Big, + #[sea_orm(string_value = "S")] + Small, +} +``` + +### Manual Implementation + +```rust +use sea_orm::entity::prelude::*; + +// Implementing it manually +#[derive(Debug, PartialEq, EnumIter)] +pub enum Category { + Big, + Small, +} + +impl ActiveEnum for Category { + // The macro attribute `rs_type` is being pasted here + type Value = String; + + // Will be atomically generated by `DeriveActiveEnum` + fn name() -> String { + "category".to_owned() + } + + // Will be atomically generated by `DeriveActiveEnum` + fn to_value(&self) -> Self::Value { + match self { + Self::Big => "B", + Self::Small => "S", + } + .to_owned() + } + + // Will be atomically generated by `DeriveActiveEnum` + fn try_from_value(v: &Self::Value) -> Result { + match v.as_ref() { + "B" => Ok(Self::Big), + "S" => Ok(Self::Small), + _ => Err(DbErr::Type(format!( + "unexpected value for Category enum: {}", + v + ))), + } + } + + fn db_type() -> ColumnDef { + // The macro attribute `db_type` is being pasted here + ColumnType::String(Some(1)).def() + } +} +``` + +## Using ActiveEnum on Model + +```rust +use sea_orm::entity::prelude::*; + +// Define the `Category` active enum +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "String(Some(1))")] +pub enum Category { + #[sea_orm(string_value = "B")] + Big, + #[sea_orm(string_value = "S")] + Small, +} + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "active_enum")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + // Represents a db column using `Category` active enum + pub category: Category, + pub category_opt: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} +``` diff --git a/SeaORM/docs/04-basic-crud/_category_.json b/SeaORM/docs/05-basic-crud/_category_.json similarity index 100% rename from SeaORM/docs/04-basic-crud/_category_.json rename to SeaORM/docs/05-basic-crud/_category_.json diff --git a/SeaORM/docs/05-relation/01-one-to-one.md b/SeaORM/docs/06-relation/01-one-to-one.md similarity index 100% rename from SeaORM/docs/05-relation/01-one-to-one.md rename to SeaORM/docs/06-relation/01-one-to-one.md diff --git a/SeaORM/docs/05-relation/02-one-to-many.md b/SeaORM/docs/06-relation/02-one-to-many.md similarity index 100% rename from SeaORM/docs/05-relation/02-one-to-many.md rename to SeaORM/docs/06-relation/02-one-to-many.md diff --git a/SeaORM/docs/05-relation/03-many-to-many.md b/SeaORM/docs/06-relation/03-many-to-many.md similarity index 100% rename from SeaORM/docs/05-relation/03-many-to-many.md rename to SeaORM/docs/06-relation/03-many-to-many.md diff --git a/SeaORM/docs/07-advanced-query/04-advanced-relations.md b/SeaORM/docs/06-relation/04-multiple-join-paths-between-two-entities.md similarity index 59% rename from SeaORM/docs/07-advanced-query/04-advanced-relations.md rename to SeaORM/docs/06-relation/04-multiple-join-paths-between-two-entities.md index 95c0beabc71..678694a3df4 100644 --- a/SeaORM/docs/07-advanced-query/04-advanced-relations.md +++ b/SeaORM/docs/06-relation/04-multiple-join-paths-between-two-entities.md @@ -1,42 +1,4 @@ -# Advanced Relations - -## Custom Joins - -You can use the `join` method to construct complex join select query. It takes any `RelationDef` defined in entity file, you can define relation with `belongs_to` method as well. Join type is specified using `JoinType` such as inner join, left join and right join. - -```rust -use sea_orm::{JoinType, RelationTrait}; -use sea_query::Expr; - -assert_eq!( - cake::Entity::find() - .column_as(filling::Column::Id.count(), "count") - .join_rev( - // construct `RelationDef` on the fly - JoinType::InnerJoin, - cake_filling::Entity::belongs_to(cake::Entity) - .from(cake_filling::Column::CakeId) - .to(cake::Column::Id) - .into() - ) - // reuse a `Relation` from existing Entity - .join(JoinType::InnerJoin, cake_filling::Relation::Filling.def()) - .group_by(cake::Column::Id) - .having(filling::Column::Id.count().equals(Expr::value(2))) - .build(DbBackend::MySql) - .to_string(), - [ - "SELECT `cake`.`id`, `cake`.`name`, COUNT(`filling`.`id`) AS `count` FROM `cake`", - "INNER JOIN `cake_filling` ON `cake_filling`.`cake_id` = `cake`.`id`", - "INNER JOIN `filling` ON `cake_filling`.`filling_id` = `filling`.`id`", - "GROUP BY `cake`.`id`", - "HAVING COUNT(`filling`.`id`) = 2", - ] - .join(" ") -); -``` - -## Linked +# Multiple Join Paths Between Two Entities If you have multiple join paths between two tables or have complex joins that involve multiple tables, you can define it with [`Linked`](https://docs.rs/sea-orm/0.*/sea_orm/entity/trait.Linked.html). Take [this](https://github.com/SeaQL/sea-orm/blob/master/src/tests_cfg/cake.rs) as an example. We join cake and filling via an intermediate cake_filling table. @@ -88,7 +50,7 @@ assert_eq!( ### Eager Loading -Use the [`find_also_linked`](https://docs.rs/sea-orm/0.2.1/sea_orm/entity/prelude/struct.Select.html#method.find_also_linked) method. +Use the [`find_also_linked`](https://docs.rs/sea-orm/0.*/sea_orm/entity/prelude/struct.Select.html#method.find_also_linked) method. All linked models are loaded at once. This provides minimum overhead on database round trips compared to lazy loading. diff --git a/SeaORM/docs/06-relation/05-self-referencing.md b/SeaORM/docs/06-relation/05-self-referencing.md new file mode 100644 index 00000000000..e774c33bc85 --- /dev/null +++ b/SeaORM/docs/06-relation/05-self-referencing.md @@ -0,0 +1,88 @@ +# Self Referencing + +From previous section, you learn the [`Linked`](https://docs.rs/sea-orm/0.*/sea_orm/entity/trait.Linked.html) trait. It can also help you define self referencing relations. + +Defining an Entity that reference itself. + +```rust +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "self_join")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub uuid: Uuid, + pub uuid_ref: Option, + pub time: Option