From 10a5a34cd9280cddfa06fc58b3d5cf281a58a550 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 10 Sep 2021 17:48:25 +0800 Subject: [PATCH 01/32] Move files --- sea-orm-codegen/src/entity/writer.rs | 16 ++++++++-------- .../tests/{entity => expanded}/cake.rs | 0 .../tests/{entity => expanded}/cake_filling.rs | 0 .../tests/{entity => expanded}/filling.rs | 0 .../tests/{entity => expanded}/fruit.rs | 0 .../tests/{entity => expanded}/mod.rs | 0 .../tests/{entity => expanded}/prelude.rs | 0 .../tests/{entity => expanded}/vendor.rs | 0 8 files changed, 8 insertions(+), 8 deletions(-) rename sea-orm-codegen/tests/{entity => expanded}/cake.rs (100%) rename sea-orm-codegen/tests/{entity => expanded}/cake_filling.rs (100%) rename sea-orm-codegen/tests/{entity => expanded}/filling.rs (100%) rename sea-orm-codegen/tests/{entity => expanded}/fruit.rs (100%) rename sea-orm-codegen/tests/{entity => expanded}/mod.rs (100%) rename sea-orm-codegen/tests/{entity => expanded}/prelude.rs (100%) rename sea-orm-codegen/tests/{entity => expanded}/vendor.rs (100%) diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index 19e9af1c..ad356872 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -308,12 +308,12 @@ mod tests { use sea_query::ColumnType; use std::io::{self, BufRead, BufReader}; - const ENTITY_FILES: [&str; 5] = [ - include_str!("../../tests/entity/cake.rs"), - include_str!("../../tests/entity/cake_filling.rs"), - include_str!("../../tests/entity/filling.rs"), - include_str!("../../tests/entity/fruit.rs"), - include_str!("../../tests/entity/vendor.rs"), + const EXPANDED_ENTITY_FILES: [&str; 5] = [ + include_str!("../../tests/expanded/cake.rs"), + include_str!("../../tests/expanded/cake_filling.rs"), + include_str!("../../tests/expanded/filling.rs"), + include_str!("../../tests/expanded/fruit.rs"), + include_str!("../../tests/expanded/vendor.rs"), ]; fn setup() -> Vec { @@ -506,10 +506,10 @@ mod tests { fn test_gen_code_blocks() -> io::Result<()> { let entities = setup(); - assert_eq!(entities.len(), ENTITY_FILES.len()); + assert_eq!(entities.len(), EXPANDED_ENTITY_FILES.len()); for (i, entity) in entities.iter().enumerate() { - let mut reader = BufReader::new(ENTITY_FILES[i].as_bytes()); + let mut reader = BufReader::new(EXPANDED_ENTITY_FILES[i].as_bytes()); let mut lines: Vec = Vec::new(); reader.read_until(b';', &mut Vec::new())?; diff --git a/sea-orm-codegen/tests/entity/cake.rs b/sea-orm-codegen/tests/expanded/cake.rs similarity index 100% rename from sea-orm-codegen/tests/entity/cake.rs rename to sea-orm-codegen/tests/expanded/cake.rs diff --git a/sea-orm-codegen/tests/entity/cake_filling.rs b/sea-orm-codegen/tests/expanded/cake_filling.rs similarity index 100% rename from sea-orm-codegen/tests/entity/cake_filling.rs rename to sea-orm-codegen/tests/expanded/cake_filling.rs diff --git a/sea-orm-codegen/tests/entity/filling.rs b/sea-orm-codegen/tests/expanded/filling.rs similarity index 100% rename from sea-orm-codegen/tests/entity/filling.rs rename to sea-orm-codegen/tests/expanded/filling.rs diff --git a/sea-orm-codegen/tests/entity/fruit.rs b/sea-orm-codegen/tests/expanded/fruit.rs similarity index 100% rename from sea-orm-codegen/tests/entity/fruit.rs rename to sea-orm-codegen/tests/expanded/fruit.rs diff --git a/sea-orm-codegen/tests/entity/mod.rs b/sea-orm-codegen/tests/expanded/mod.rs similarity index 100% rename from sea-orm-codegen/tests/entity/mod.rs rename to sea-orm-codegen/tests/expanded/mod.rs diff --git a/sea-orm-codegen/tests/entity/prelude.rs b/sea-orm-codegen/tests/expanded/prelude.rs similarity index 100% rename from sea-orm-codegen/tests/entity/prelude.rs rename to sea-orm-codegen/tests/expanded/prelude.rs diff --git a/sea-orm-codegen/tests/entity/vendor.rs b/sea-orm-codegen/tests/expanded/vendor.rs similarity index 100% rename from sea-orm-codegen/tests/entity/vendor.rs rename to sea-orm-codegen/tests/expanded/vendor.rs From 9c3aba8c0ebfd1120584af694839e0fcbb5cb635 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 10 Sep 2021 22:27:50 +0800 Subject: [PATCH 02/32] codegen of compact entity files --- sea-orm-codegen/Cargo.toml | 5 +- sea-orm-codegen/src/entity/base_entity.rs | 22 ++- sea-orm-codegen/src/entity/relation.rs | 73 ++++++++- sea-orm-codegen/src/entity/writer.rs | 146 ++++++++++++++++-- sea-orm-codegen/tests/compact/cake.rs | 34 ++++ sea-orm-codegen/tests/compact/cake_filling.rs | 46 ++++++ sea-orm-codegen/tests/compact/filling.rs | 33 ++++ sea-orm-codegen/tests/compact/fruit.rs | 38 +++++ sea-orm-codegen/tests/compact/mod.rs | 9 ++ sea-orm-codegen/tests/compact/prelude.rs | 7 + sea-orm-codegen/tests/compact/vendor.rs | 30 ++++ src/query/helper.rs | 4 +- 12 files changed, 428 insertions(+), 19 deletions(-) create mode 100644 sea-orm-codegen/tests/compact/cake.rs create mode 100644 sea-orm-codegen/tests/compact/cake_filling.rs create mode 100644 sea-orm-codegen/tests/compact/filling.rs create mode 100644 sea-orm-codegen/tests/compact/fruit.rs create mode 100644 sea-orm-codegen/tests/compact/mod.rs create mode 100644 sea-orm-codegen/tests/compact/prelude.rs create mode 100644 sea-orm-codegen/tests/compact/vendor.rs diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index 56cd72ae..7e564b0d 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -15,7 +15,7 @@ name = "sea_orm_codegen" path = "src/lib.rs" [dependencies] -sea-query = { version = "^0.15" } +sea-query = { version = "0.16.1", git = "https://github.com/SeaQL/sea-query.git", branch = "foreign-key-getters" } syn = { version = "^1", default-features = false, features = [ "derive", "parsing", @@ -25,3 +25,6 @@ syn = { version = "^1", default-features = false, features = [ quote = "^1" heck = "^0.3" proc-macro2 = "^1" + +[dev-dependencies] +pretty_assertions = { version = "^0.7" } diff --git a/sea-orm-codegen/src/entity/base_entity.rs b/sea-orm-codegen/src/entity/base_entity.rs index 7b28f9e4..02f9ee21 100644 --- a/sea-orm-codegen/src/entity/base_entity.rs +++ b/sea-orm-codegen/src/entity/base_entity.rs @@ -91,6 +91,10 @@ impl Entity { self.relations.iter().map(|rel| rel.get_def()).collect() } + pub fn get_relation_attrs(&self) -> Vec { + self.relations.iter().map(|rel| rel.get_attrs()).collect() + } + pub fn get_relation_rel_types(&self) -> Vec { self.relations .iter() @@ -168,7 +172,7 @@ impl Entity { mod tests { use crate::{Column, Entity, PrimaryKey, Relation, RelationType}; use quote::format_ident; - use sea_query::ColumnType; + use sea_query::{ColumnType, ForeignKeyAction}; fn setup() -> Entity { Entity { @@ -195,12 +199,16 @@ mod tests { columns: vec!["id".to_owned()], ref_columns: vec!["cake_id".to_owned()], rel_type: RelationType::HasOne, + on_delete: Some(ForeignKeyAction::Cascade), + on_update: Some(ForeignKeyAction::Cascade), }, Relation { ref_table: "filling".to_owned(), columns: vec!["id".to_owned()], ref_columns: vec!["cake_id".to_owned()], rel_type: RelationType::HasOne, + on_delete: Some(ForeignKeyAction::Cascade), + on_update: Some(ForeignKeyAction::Cascade), }, ], conjunct_relations: vec![], @@ -347,6 +355,18 @@ mod tests { } } + #[test] + fn test_get_relation_attrs() { + let entity = setup(); + + for (i, elem) in entity.get_relation_attrs().into_iter().enumerate() { + assert_eq!( + elem.to_string(), + entity.relations[i].get_attrs().to_string() + ); + } + } + #[test] fn test_get_relation_rel_types() { let entity = setup(); diff --git a/sea-orm-codegen/src/entity/relation.rs b/sea-orm-codegen/src/entity/relation.rs index d675137a..f1e9b441 100644 --- a/sea-orm-codegen/src/entity/relation.rs +++ b/sea-orm-codegen/src/entity/relation.rs @@ -1,7 +1,7 @@ use heck::{CamelCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use sea_query::TableForeignKey; +use sea_query::{ForeignKeyAction, TableForeignKey}; #[derive(Clone, Debug)] pub enum RelationType { @@ -16,6 +16,8 @@ pub struct Relation { pub(crate) columns: Vec, pub(crate) ref_columns: Vec, pub(crate) rel_type: RelationType, + pub(crate) on_update: Option, + pub(crate) on_delete: Option, } impl Relation { @@ -49,6 +51,53 @@ impl Relation { } } + pub fn get_attrs(&self) -> TokenStream { + let rel_type = self.get_rel_type(); + let ref_table_snake_case = self.get_ref_table_snake_case(); + let ref_entity = format!("super::{}::Entity", ref_table_snake_case); + match self.rel_type { + RelationType::HasOne | RelationType::HasMany => { + quote! { + #[sea_orm(#rel_type = #ref_entity)] + } + } + RelationType::BelongsTo => { + let column_camel_case = self.get_column_camel_case(); + let ref_column_camel_case = self.get_ref_column_camel_case(); + let from = format!("Column::{}", column_camel_case); + let to = format!( + "super::{}::Column::{}", + ref_table_snake_case, ref_column_camel_case + ); + let on_update = if let Some(action) = &self.on_update { + let action = Self::get_foreign_key_action(action); + quote! { + on_update = #action, + } + } else { + TokenStream::new() + }; + let on_delete = if let Some(action) = &self.on_delete { + let action = Self::get_foreign_key_action(action); + quote! { + on_delete = #action, + } + } else { + TokenStream::new() + }; + quote! { + #[sea_orm( + #rel_type = #ref_entity, + from = #from, + to = #to, + #on_update + #on_delete + )] + } + } + } + } + pub fn get_rel_type(&self) -> Ident { match self.rel_type { RelationType::HasOne => format_ident!("has_one"), @@ -64,6 +113,17 @@ impl Relation { pub fn get_ref_column_camel_case(&self) -> Ident { format_ident!("{}", self.ref_columns[0].to_camel_case()) } + + pub fn get_foreign_key_action(action: &ForeignKeyAction) -> String { + match action { + ForeignKeyAction::Restrict => "Restrict", + ForeignKeyAction::Cascade => "Cascade", + ForeignKeyAction::SetNull => "SetNull", + ForeignKeyAction::NoAction => "NoAction", + ForeignKeyAction::SetDefault => "SetDefault", + } + .to_owned() + } } impl From<&TableForeignKey> for Relation { @@ -75,11 +135,15 @@ impl From<&TableForeignKey> for Relation { let columns = tbl_fk.get_columns(); let ref_columns = tbl_fk.get_ref_columns(); let rel_type = RelationType::BelongsTo; + let on_delete = tbl_fk.get_on_delete(); + let on_update = tbl_fk.get_on_update(); Self { ref_table, columns, ref_columns, rel_type, + on_delete, + on_update, } } } @@ -88,6 +152,7 @@ impl From<&TableForeignKey> for Relation { mod tests { use crate::{Relation, RelationType}; use proc_macro2::TokenStream; + use sea_query::ForeignKeyAction; fn setup() -> Vec { vec![ @@ -96,18 +161,24 @@ mod tests { columns: vec!["id".to_owned()], ref_columns: vec!["cake_id".to_owned()], rel_type: RelationType::HasOne, + on_delete: None, + on_update: None, }, Relation { ref_table: "filling".to_owned(), columns: vec!["filling_id".to_owned()], ref_columns: vec!["id".to_owned()], rel_type: RelationType::BelongsTo, + on_delete: Some(ForeignKeyAction::Cascade), + on_update: Some(ForeignKeyAction::Cascade), }, Relation { ref_table: "filling".to_owned(), columns: vec!["filling_id".to_owned()], ref_columns: vec!["id".to_owned()], rel_type: RelationType::HasMany, + on_delete: Some(ForeignKeyAction::Cascade), + on_update: None, }, ] } diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index ad356872..75229835 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -31,7 +31,7 @@ impl EntityWriter { .map(|entity| { let mut lines = Vec::new(); Self::write_doc_comment(&mut lines); - let code_blocks = Self::gen_code_blocks(entity); + let code_blocks = Self::gen_expanded_code_blocks(entity); Self::write(&mut lines, code_blocks); OutputFile { name: format!("{}.rs", entity.get_table_name_snake_case()), @@ -97,7 +97,7 @@ impl EntityWriter { lines.push("".to_owned()); } - pub fn gen_code_blocks(entity: &Entity) -> Vec { + pub fn gen_expanded_code_blocks(entity: &Entity) -> Vec { let mut code_blocks = vec![ Self::gen_import(), Self::gen_entity_struct(), @@ -116,6 +116,23 @@ impl EntityWriter { code_blocks } + pub fn gen_compact_code_blocks(entity: &Entity) -> Vec { + let mut code_blocks = vec![Self::gen_import(), Self::gen_compact_model_struct(entity)]; + let relation_defs = if entity.get_relation_ref_tables_camel_case().is_empty() { + vec![ + Self::gen_relation_enum(entity), + Self::gen_impl_relation_trait(entity), + ] + } else { + vec![Self::gen_compact_relation_enum(entity)] + }; + code_blocks.extend(relation_defs); + code_blocks.extend(Self::gen_impl_related(entity)); + code_blocks.extend(Self::gen_impl_conjunct_related(entity)); + code_blocks.extend(vec![Self::gen_impl_active_model_behavior()]); + code_blocks + } + pub fn gen_import() -> TokenStream { quote! { use sea_orm::entity::prelude::*; @@ -297,6 +314,54 @@ impl EntityWriter { pub use super::#table_name_snake_case_ident::Entity as #table_name_camel_case_ident; } } + + pub fn gen_compact_model_struct(entity: &Entity) -> TokenStream { + let table_name = entity.table_name.as_str(); + let column_names_snake_case = entity.get_column_names_snake_case(); + let column_rs_types = entity.get_column_rs_types(); + let primary_keys: Vec = entity + .primary_keys + .iter() + .map(|pk| pk.name.clone()) + .collect(); + let attrs: Vec = entity + .columns + .iter() + .map(|col| { + if !primary_keys.contains(&col.name) { + TokenStream::new() + } else { + quote! { + #[sea_orm(primary_key)] + } + } + }) + .collect(); + quote! { + #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] + #[sea_orm(table_name = #table_name)] + pub struct Model { + #( + #attrs + pub #column_names_snake_case: #column_rs_types, + )* + } + } + } + + pub fn gen_compact_relation_enum(entity: &Entity) -> TokenStream { + let relation_ref_tables_camel_case = entity.get_relation_ref_tables_camel_case(); + let attrs = entity.get_relation_attrs(); + quote! { + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] + pub enum Relation { + #( + #attrs + #relation_ref_tables_camel_case, + )* + } + } + } } #[cfg(test)] @@ -304,18 +369,11 @@ mod tests { use crate::{ Column, ConjunctRelation, Entity, EntityWriter, PrimaryKey, Relation, RelationType, }; + use pretty_assertions::assert_eq; use proc_macro2::TokenStream; - use sea_query::ColumnType; + use sea_query::{ColumnType, ForeignKeyAction}; use std::io::{self, BufRead, BufReader}; - const EXPANDED_ENTITY_FILES: [&str; 5] = [ - include_str!("../../tests/expanded/cake.rs"), - include_str!("../../tests/expanded/cake_filling.rs"), - include_str!("../../tests/expanded/filling.rs"), - include_str!("../../tests/expanded/fruit.rs"), - include_str!("../../tests/expanded/vendor.rs"), - ]; - fn setup() -> Vec { vec![ Entity { @@ -341,6 +399,8 @@ mod tests { columns: vec![], ref_columns: vec![], rel_type: RelationType::HasMany, + on_delete: None, + on_update: None, }], conjunct_relations: vec![ConjunctRelation { via: "cake_filling".to_owned(), @@ -374,12 +434,16 @@ mod tests { columns: vec!["cake_id".to_owned()], ref_columns: vec!["id".to_owned()], rel_type: RelationType::BelongsTo, + on_delete: Some(ForeignKeyAction::Cascade), + on_update: Some(ForeignKeyAction::Cascade), }, Relation { ref_table: "filling".to_owned(), columns: vec!["filling_id".to_owned()], ref_columns: vec!["id".to_owned()], rel_type: RelationType::BelongsTo, + on_delete: Some(ForeignKeyAction::Cascade), + on_update: Some(ForeignKeyAction::Cascade), }, ], conjunct_relations: vec![], @@ -450,12 +514,16 @@ mod tests { columns: vec!["cake_id".to_owned()], ref_columns: vec!["id".to_owned()], rel_type: RelationType::BelongsTo, + on_delete: None, + on_update: None, }, Relation { ref_table: "vendor".to_owned(), columns: vec![], ref_columns: vec![], rel_type: RelationType::HasMany, + on_delete: None, + on_update: None, }, ], conjunct_relations: vec![], @@ -493,6 +561,8 @@ mod tests { columns: vec!["fruit_id".to_owned()], ref_columns: vec!["id".to_owned()], rel_type: RelationType::BelongsTo, + on_delete: None, + on_update: None, }], conjunct_relations: vec![], primary_keys: vec![PrimaryKey { @@ -503,13 +573,20 @@ mod tests { } #[test] - fn test_gen_code_blocks() -> io::Result<()> { + fn test_gen_expanded_code_blocks() -> io::Result<()> { let entities = setup(); + const ENTITY_FILES: [&str; 5] = [ + include_str!("../../tests/expanded/cake.rs"), + include_str!("../../tests/expanded/cake_filling.rs"), + include_str!("../../tests/expanded/filling.rs"), + include_str!("../../tests/expanded/fruit.rs"), + include_str!("../../tests/expanded/vendor.rs"), + ]; - assert_eq!(entities.len(), EXPANDED_ENTITY_FILES.len()); + assert_eq!(entities.len(), ENTITY_FILES.len()); for (i, entity) in entities.iter().enumerate() { - let mut reader = BufReader::new(EXPANDED_ENTITY_FILES[i].as_bytes()); + let mut reader = BufReader::new(ENTITY_FILES[i].as_bytes()); let mut lines: Vec = Vec::new(); reader.read_until(b';', &mut Vec::new())?; @@ -521,7 +598,46 @@ mod tests { } let content = lines.join(""); let expected: TokenStream = content.parse().unwrap(); - let generated = EntityWriter::gen_code_blocks(entity) + let generated = EntityWriter::gen_expanded_code_blocks(entity) + .into_iter() + .skip(1) + .fold(TokenStream::new(), |mut acc, tok| { + acc.extend(tok); + acc + }); + assert_eq!(expected.to_string(), generated.to_string()); + } + + Ok(()) + } + + #[test] + fn test_gen_compact_code_blocks() -> io::Result<()> { + let entities = setup(); + const ENTITY_FILES: [&str; 5] = [ + include_str!("../../tests/compact/cake.rs"), + include_str!("../../tests/compact/cake_filling.rs"), + include_str!("../../tests/compact/filling.rs"), + include_str!("../../tests/compact/fruit.rs"), + include_str!("../../tests/compact/vendor.rs"), + ]; + + assert_eq!(entities.len(), ENTITY_FILES.len()); + + for (i, entity) in entities.iter().enumerate() { + let mut reader = BufReader::new(ENTITY_FILES[i].as_bytes()); + let mut lines: Vec = Vec::new(); + + reader.read_until(b';', &mut Vec::new())?; + + let mut line = String::new(); + while reader.read_line(&mut line)? > 0 { + lines.push(line.to_owned()); + line.clear(); + } + let content = lines.join(""); + let expected: TokenStream = content.parse().unwrap(); + let generated = EntityWriter::gen_compact_code_blocks(entity) .into_iter() .skip(1) .fold(TokenStream::new(), |mut acc, tok| { diff --git a/sea-orm-codegen/tests/compact/cake.rs b/sea-orm-codegen/tests/compact/cake.rs new file mode 100644 index 00000000..4a64611e --- /dev/null +++ b/sea-orm-codegen/tests/compact/cake.rs @@ -0,0 +1,34 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "cake")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub name: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::fruit::Entity")] + Fruit, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Fruit.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::cake_filling::Relation::Filling.def() + } + fn via() -> Option { + Some(super::cake_filling::Relation::Cake.def().rev()) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/tests/compact/cake_filling.rs b/sea-orm-codegen/tests/compact/cake_filling.rs new file mode 100644 index 00000000..af966c66 --- /dev/null +++ b/sea-orm-codegen/tests/compact/cake_filling.rs @@ -0,0 +1,46 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "_cake_filling_")] +pub struct Model { + #[sea_orm(primary_key)] + pub cake_id: i32, + #[sea_orm(primary_key)] + pub filling_id: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::cake::Entity", + from = "Column::CakeId", + to = "super::cake::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Cake, + #[sea_orm( + belongs_to = "super::filling::Entity", + from = "Column::FillingId", + to = "super::filling::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Filling, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Cake.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Filling.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/tests/compact/filling.rs b/sea-orm-codegen/tests/compact/filling.rs new file mode 100644 index 00000000..820f65c8 --- /dev/null +++ b/sea-orm-codegen/tests/compact/filling.rs @@ -0,0 +1,33 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "filling")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub name: String, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("No RelationDef"), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::cake_filling::Relation::Cake.def() + } + fn via() -> Option { + Some(super::cake_filling::Relation::Filling.def().rev()) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/tests/compact/fruit.rs b/sea-orm-codegen/tests/compact/fruit.rs new file mode 100644 index 00000000..6399a51f --- /dev/null +++ b/sea-orm-codegen/tests/compact/fruit.rs @@ -0,0 +1,38 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "fruit")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub name: String, + pub cake_id: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::cake::Entity", + from = "Column::CakeId", + to = "super::cake::Column::Id", + )] + Cake, + #[sea_orm(has_many = "super::vendor::Entity")] + Vendor, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Cake.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Vendor.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/tests/compact/mod.rs b/sea-orm-codegen/tests/compact/mod.rs new file mode 100644 index 00000000..5a8c6c21 --- /dev/null +++ b/sea-orm-codegen/tests/compact/mod.rs @@ -0,0 +1,9 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +pub mod prelude; + +pub mod cake; +pub mod cake_filling; +pub mod filling; +pub mod fruit; +pub mod vendor; diff --git a/sea-orm-codegen/tests/compact/prelude.rs b/sea-orm-codegen/tests/compact/prelude.rs new file mode 100644 index 00000000..b4e85c78 --- /dev/null +++ b/sea-orm-codegen/tests/compact/prelude.rs @@ -0,0 +1,7 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +pub use super::cake::Entity as Cake; +pub use super::cake_filling::Entity as CakeFilling; +pub use super::filling::Entity as Filling; +pub use super::fruit::Entity as Fruit; +pub use super::vendor::Entity as Vendor; diff --git a/sea-orm-codegen/tests/compact/vendor.rs b/sea-orm-codegen/tests/compact/vendor.rs new file mode 100644 index 00000000..314eb396 --- /dev/null +++ b/sea-orm-codegen/tests/compact/vendor.rs @@ -0,0 +1,30 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "vendor")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub name: String, + pub fruit_id: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::fruit::Entity", + from = "Column::FruitId", + to = "super::fruit::Column::Id", + )] + Fruit, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Fruit.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/query/helper.rs b/src/query/helper.rs index 7aeb9f0b..d93595f1 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -3,7 +3,9 @@ use crate::{ PrimaryKeyToColumn, RelationDef, }; pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement}; -use sea_query::{Expr, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef}; +use sea_query::{ + Expr, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef, +}; // LINT: when the column does not appear in tables selected from // LINT: when there is a group by clause, but some columns don't have aggregate functions From a6f117a908943c835a3feb6c12ac920a3fa29465 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 10 Sep 2021 23:08:30 +0800 Subject: [PATCH 03/32] sea-orm-cli with `--expanded-format` & `--compact-format` flags --- sea-orm-cli/Cargo.toml | 4 ++-- sea-orm-cli/src/cli.rs | 14 ++++++++++++++ sea-orm-cli/src/main.rs | 3 ++- sea-orm-codegen/Cargo.toml | 2 +- sea-orm-codegen/src/entity/writer.rs | 12 ++++++++---- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 46340f7b..5646ffc7 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -22,8 +22,8 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm = { version = "^0.1.2", features = [ "sqlx-all" ] } -sea-orm-codegen = { version = "^0.2.0" } -sea-schema = { version = "^0.2.7", default-features = false, features = [ +sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } +sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", branch = "update-sea-query-version", default-features = false, features = [ "sqlx-mysql", "sqlx-postgres", "discovery", diff --git a/sea-orm-cli/src/cli.rs b/sea-orm-cli/src/cli.rs index 8f2919fb..400374c5 100644 --- a/sea-orm-cli/src/cli.rs +++ b/sea-orm-cli/src/cli.rs @@ -40,6 +40,20 @@ pub fn build_cli() -> App<'static, 'static> { .long("include-hidden-tables") .help("Generate entity file for hidden tables (i.e. table name starts with an underscore)") .takes_value(false), + ) + .arg( + Arg::with_name("EXPANDED_FORMAT") + .long("expanded-format") + .help("Generate entity file of expanded format") + .takes_value(false) + .conflicts_with("COMPACT_FORMAT"), + ) + .arg( + Arg::with_name("COMPACT_FORMAT") + .long("compact-format") + .help("Generate entity file of compact format") + .takes_value(false) + .conflicts_with("EXPANDED_FORMAT"), ), ) .setting(AppSettings::SubcommandRequiredElseHelp); diff --git a/sea-orm-cli/src/main.rs b/sea-orm-cli/src/main.rs index c3cc60dd..2f51aefb 100644 --- a/sea-orm-cli/src/main.rs +++ b/sea-orm-cli/src/main.rs @@ -25,6 +25,7 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box bool { if include_hidden_tables { true @@ -66,7 +67,7 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box WriterOutput { + pub fn generate(self, expanded_format: bool) -> WriterOutput { let mut files = Vec::new(); - files.extend(self.write_entities()); + files.extend(self.write_entities(expanded_format)); files.push(self.write_mod()); files.push(self.write_prelude()); WriterOutput { files } } - pub fn write_entities(&self) -> Vec { + pub fn write_entities(&self, expanded_format: bool) -> Vec { self.entities .iter() .map(|entity| { let mut lines = Vec::new(); Self::write_doc_comment(&mut lines); - let code_blocks = Self::gen_expanded_code_blocks(entity); + let code_blocks = if expanded_format { + Self::gen_expanded_code_blocks(entity) + } else { + Self::gen_compact_code_blocks(entity) + }; Self::write(&mut lines, code_blocks); OutputFile { name: format!("{}.rs", entity.get_table_name_snake_case()), From f801590b9bbbf12712c92cf5004d145e917434f5 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 10 Sep 2021 23:21:37 +0800 Subject: [PATCH 04/32] Remove unused sea-orm dep --- sea-orm-cli/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 5646ffc7..8c9fd17e 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -21,7 +21,6 @@ path = "src/main.rs" clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } -sea-orm = { version = "^0.1.2", features = [ "sqlx-all" ] } sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", branch = "update-sea-query-version", default-features = false, features = [ "sqlx-mysql", From 236bc56f03963e67e7f8f86cc50980fca4af245f Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 11 Sep 2021 15:45:05 +0800 Subject: [PATCH 05/32] Persist posts_per_page across pages --- examples/rocket_example/src/main.rs | 3 ++- examples/rocket_example/templates/index.html.tera | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/rocket_example/src/main.rs b/examples/rocket_example/src/main.rs index d1f23244..1a275200 100644 --- a/examples/rocket_example/src/main.rs +++ b/examples/rocket_example/src/main.rs @@ -26,7 +26,7 @@ type Result> = std::result::Result Template { @@ -97,6 +97,7 @@ async fn list( posts: posts, flash: flash, page: page, + posts_per_page: posts_per_page, num_pages: num_pages, }, ) diff --git a/examples/rocket_example/templates/index.html.tera b/examples/rocket_example/templates/index.html.tera index 0dc60fb9..0cba1b7d 100644 --- a/examples/rocket_example/templates/index.html.tera +++ b/examples/rocket_example/templates/index.html.tera @@ -27,9 +27,9 @@ {% if page == 0 %} Previous {% else %} - Previous + Previous {% endif %} | {% if page == num_pages - 1 %} Next {% else %} - Next + Next {% endif %} From 182c96e3845313f88477328b6cb0151f002a102b Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 11 Sep 2021 15:53:34 +0800 Subject: [PATCH 06/32] Fix clippy warning --- src/executor/query.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/executor/query.rs b/src/executor/query.rs index a96292e7..ba8c8169 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -1,4 +1,6 @@ -use crate::{debug_print, DbErr}; +#[cfg(feature = "mock")] +use crate::debug_print; +use crate::DbErr; use std::fmt; #[derive(Debug)] From 8d70137508a8a66f15906c9b346a4a8bc384f1e0 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 11 Sep 2021 23:21:49 +0800 Subject: [PATCH 07/32] Docs --- README.md | 5 ++--- src/lib.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4dbf6110..8c8ef920 100644 --- a/README.md +++ b/README.md @@ -81,9 +81,8 @@ let pear = fruit::ActiveModel { }; // insert one -let res = Fruit::insert(pear).exec(db).await?; - -println!("InsertResult: {}", res.last_insert_id); +let pear = pear.insert(db).await?; +# // insert many Fruit::insert_many(vec![apple, pear]).exec(db).await?; diff --git a/src/lib.rs b/src/lib.rs index 44c1be64..17a401d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,9 +94,8 @@ //! }; //! //! // insert one -//! let res = Fruit::insert(pear).exec(db).await?; -//! -//! println!("InsertResult: {}", res.last_insert_id); +//! let pear = pear.insert(db).await?; +//! # //! # Ok(()) //! # } //! # async fn function2(db: &DbConn) -> Result<(), DbErr> { From 1815e3040514fe414c646fb4b771287758ecf9f5 Mon Sep 17 00:00:00 2001 From: Ari Seyhun Date: Sun, 12 Sep 2021 20:50:28 +0930 Subject: [PATCH 08/32] Add `DateTimeWithTimeZone` support for `DeriveEntityModel` --- sea-orm-macros/src/derives/entity_model.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index 004970c5..bd6b332d 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -163,7 +163,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res "bool" => quote! { Boolean }, "NaiveDate" => quote! { Date }, "NaiveTime" => quote! { Time }, - "DateTime" | "NaiveDateTime" => quote! { DateTime }, + "DateTime" | "NaiveDateTime" | "DateTimeWithTimeZone" => quote! { DateTime }, "Uuid" => quote! { Uuid }, "Json" => quote! { Json }, "Decimal" => quote! { Decimal }, From 2ac8fe664e3a5102190ac03901e66b51dee603ed Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 11 Sep 2021 23:21:49 +0800 Subject: [PATCH 09/32] Docs --- README.md | 4 +--- src/lib.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4dbf6110..1bd05a58 100644 --- a/README.md +++ b/README.md @@ -81,9 +81,7 @@ let pear = fruit::ActiveModel { }; // insert one -let res = Fruit::insert(pear).exec(db).await?; - -println!("InsertResult: {}", res.last_insert_id); +let pear = pear.insert(db).await?; // insert many Fruit::insert_many(vec![apple, pear]).exec(db).await?; diff --git a/src/lib.rs b/src/lib.rs index 44c1be64..3a281ecd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,9 +94,7 @@ //! }; //! //! // insert one -//! let res = Fruit::insert(pear).exec(db).await?; -//! -//! println!("InsertResult: {}", res.last_insert_id); +//! let pear = pear.insert(db).await?; //! # Ok(()) //! # } //! # async fn function2(db: &DbConn) -> Result<(), DbErr> { From 363b606d2c04fc654de36fc84c85f0ce474b54bc Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 13 Sep 2021 21:50:18 +0800 Subject: [PATCH 10/32] Docs --- README.md | 1 + src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 1bd05a58..8c8ef920 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ let pear = fruit::ActiveModel { // insert one let pear = pear.insert(db).await?; +# // insert many Fruit::insert_many(vec![apple, pear]).exec(db).await?; diff --git a/src/lib.rs b/src/lib.rs index 3a281ecd..17a401d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,6 +95,7 @@ //! //! // insert one //! let pear = pear.insert(db).await?; +//! # //! # Ok(()) //! # } //! # async fn function2(db: &DbConn) -> Result<(), DbErr> { From 39c5a4d134c58aba88f215c78143cdb7a740818b Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Mon, 13 Sep 2021 18:33:07 +0800 Subject: [PATCH 11/32] Derive attributes --- sea-orm-codegen/src/entity/column.rs | 15 ++++++++++++++ sea-orm-codegen/src/entity/writer.rs | 29 +++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index 0b9eb8de..fd8e1936 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -2,6 +2,7 @@ use heck::{CamelCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use sea_query::{ColumnDef, ColumnSpec, ColumnType}; +use syn::punctuated::Punctuated; #[derive(Clone, Debug)] pub struct Column { @@ -52,6 +53,20 @@ impl Column { } } + pub fn get_col_type_attrs(&self) -> Option { + let col_type = match &self.col_type { + ColumnType::Float(Some(l)) => Some(format!("Float(Some({}))", l)), + ColumnType::Double(Some(l)) => Some(format!("Double(Some({}))", l)), + ColumnType::Decimal(Some((p, s))) => Some(format!("Decimal(Some(({}, {})))", p, s)), + ColumnType::Money(Some((p, s))) => Some(format!("Money(Some({}, {}))", p, s)), + ColumnType::Custom(iden) => { + Some(format!("Custom(\"{}\".to_owned())", iden.to_string())) + } + _ => None, + }; + col_type.map(|ty| quote! { column_type = #ty }) + } + pub fn get_def(&self) -> TokenStream { let mut col_def = match &self.col_type { ColumnType::Char(s) => match s { diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index 210d43a0..5a47ce4c 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -1,6 +1,8 @@ use crate::Entity; use proc_macro2::TokenStream; use quote::quote; +use std::iter::FromIterator; +use syn::{punctuated::Punctuated, token::Comma}; #[derive(Clone, Debug)] pub struct EntityWriter { @@ -332,13 +334,30 @@ impl EntityWriter { .columns .iter() .map(|col| { - if !primary_keys.contains(&col.name) { - TokenStream::new() - } else { - quote! { - #[sea_orm(primary_key)] + let mut attrs: Punctuated<_, Comma> = Punctuated::new(); + if primary_keys.contains(&col.name) { + attrs.push(quote! { primary_key }); + if !col.auto_increment { + attrs.push(quote! { auto_increment = false }); } } + if let Some(ts) = col.get_col_type_attrs() { + attrs.extend(vec![ts]); + }; + if !attrs.is_empty() { + let mut ts = TokenStream::new(); + for (i, attr) in attrs.into_iter().enumerate() { + if i > 0 { + ts = quote! { #ts, }; + } + ts = quote! { #ts #attr }; + } + quote! { + #[sea_orm(#ts)] + } + } else { + TokenStream::new() + } }) .collect(); quote! { From 848a15856b5f9a218ee00aeb2aa087a50ef9d4e4 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 14 Sep 2021 00:04:26 +0800 Subject: [PATCH 12/32] Fix test cases --- sea-orm-codegen/tests/compact/cake_filling.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sea-orm-codegen/tests/compact/cake_filling.rs b/sea-orm-codegen/tests/compact/cake_filling.rs index af966c66..ba9ed2ca 100644 --- a/sea-orm-codegen/tests/compact/cake_filling.rs +++ b/sea-orm-codegen/tests/compact/cake_filling.rs @@ -5,9 +5,9 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] #[sea_orm(table_name = "_cake_filling_")] pub struct Model { - #[sea_orm(primary_key)] + #[sea_orm(primary_key, auto_increment = false)] pub cake_id: i32, - #[sea_orm(primary_key)] + #[sea_orm(primary_key, auto_increment = false)] pub filling_id: i32, } From 39902deaef7db7909d6cc22d0c8086a189f4164b Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 15 Sep 2021 10:44:24 +0800 Subject: [PATCH 13/32] Remove unused import --- sea-orm-codegen/src/entity/column.rs | 1 - sea-orm-codegen/src/entity/writer.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index fd8e1936..7a6b1759 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -2,7 +2,6 @@ use heck::{CamelCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use sea_query::{ColumnDef, ColumnSpec, ColumnType}; -use syn::punctuated::Punctuated; #[derive(Clone, Debug)] pub struct Column { diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index 5a47ce4c..448c5197 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -1,7 +1,6 @@ use crate::Entity; use proc_macro2::TokenStream; use quote::quote; -use std::iter::FromIterator; use syn::{punctuated::Punctuated, token::Comma}; #[derive(Clone, Debug)] From ca3dd2d2a13d8314871129bee1f0a19758846dce Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 15 Sep 2021 10:45:09 +0800 Subject: [PATCH 14/32] cargo fmt --- sea-orm-macros/src/derives/entity_model.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index bd6b332d..66c5725f 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -163,7 +163,9 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res "bool" => quote! { Boolean }, "NaiveDate" => quote! { Date }, "NaiveTime" => quote! { Time }, - "DateTime" | "NaiveDateTime" | "DateTimeWithTimeZone" => quote! { DateTime }, + "DateTime" | "NaiveDateTime" | "DateTimeWithTimeZone" => { + quote! { DateTime } + } "Uuid" => quote! { Uuid }, "Json" => quote! { Json }, "Decimal" => quote! { Decimal }, From 01011cf0f4913be2b903027e68a17fe289b8bfc2 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 15 Sep 2021 10:46:12 +0800 Subject: [PATCH 15/32] Generate macro attribute "nullable" --- sea-orm-codegen/rustfmt.toml | 3 ++- sea-orm-codegen/src/entity/column.rs | 1 + sea-orm-codegen/src/entity/writer.rs | 7 +++++-- sea-orm-codegen/tests/compact/cake.rs | 3 ++- sea-orm-codegen/tests/expanded/cake.rs | 4 ++-- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sea-orm-codegen/rustfmt.toml b/sea-orm-codegen/rustfmt.toml index 2555d91f..d7f6da65 100644 --- a/sea-orm-codegen/rustfmt.toml +++ b/sea-orm-codegen/rustfmt.toml @@ -1,3 +1,4 @@ ignore = [ - "tests/entity/*.rs", + "tests/compact/*.rs", + "tests/expanded/*.rs", ] \ No newline at end of file diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index 7a6b1759..dfec4b8e 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -58,6 +58,7 @@ impl Column { ColumnType::Double(Some(l)) => Some(format!("Double(Some({}))", l)), ColumnType::Decimal(Some((p, s))) => Some(format!("Decimal(Some(({}, {})))", p, s)), ColumnType::Money(Some((p, s))) => Some(format!("Money(Some({}, {}))", p, s)), + ColumnType::Text => Some("Text".to_owned()), ColumnType::Custom(iden) => { Some(format!("Custom(\"{}\".to_owned())", iden.to_string())) } diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index 448c5197..edfbef0b 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -342,6 +342,9 @@ impl EntityWriter { } if let Some(ts) = col.get_col_type_attrs() { attrs.extend(vec![ts]); + if !col.not_null { + attrs.push(quote! { nullable }); + } }; if !attrs.is_empty() { let mut ts = TokenStream::new(); @@ -410,9 +413,9 @@ mod tests { }, Column { name: "name".to_owned(), - col_type: ColumnType::String(Some(255)), + col_type: ColumnType::Text, auto_increment: false, - not_null: true, + not_null: false, unique: false, }, ], diff --git a/sea-orm-codegen/tests/compact/cake.rs b/sea-orm-codegen/tests/compact/cake.rs index 4a64611e..2e26257c 100644 --- a/sea-orm-codegen/tests/compact/cake.rs +++ b/sea-orm-codegen/tests/compact/cake.rs @@ -7,7 +7,8 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key)] pub id: i32, - pub name: String, + #[sea_orm(column_type = "Text", nullable)] + pub name: Option , } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/sea-orm-codegen/tests/expanded/cake.rs b/sea-orm-codegen/tests/expanded/cake.rs index 55fa279f..0b33b618 100644 --- a/sea-orm-codegen/tests/expanded/cake.rs +++ b/sea-orm-codegen/tests/expanded/cake.rs @@ -14,7 +14,7 @@ impl EntityName for Entity { #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] pub struct Model { pub id: i32, - pub name: String, + pub name: Option , } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] @@ -46,7 +46,7 @@ impl ColumnTrait for Column { fn def(&self) -> ColumnDef { match self { Self::Id => ColumnType::Integer.def(), - Self::Name => ColumnType::String(Some(255u32)).def(), + Self::Name => ColumnType::Text.def().null(), } } } From 8a4996300fcf45e422db9e36d68930d09cd67962 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Wed, 15 Sep 2021 12:16:56 +0800 Subject: [PATCH 16/32] Refactor Link --- src/entity/link.rs | 20 ++++++++++++++++++++ src/entity/mod.rs | 2 ++ src/entity/relation.rs | 16 ---------------- 3 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 src/entity/link.rs diff --git a/src/entity/link.rs b/src/entity/link.rs new file mode 100644 index 00000000..712adaa6 --- /dev/null +++ b/src/entity/link.rs @@ -0,0 +1,20 @@ +use crate::{EntityTrait, RelationDef, QuerySelect, Select}; +use sea_query::{JoinType}; + +pub type LinkDef = RelationDef; + +pub trait Linked { + type FromEntity: EntityTrait; + + type ToEntity: EntityTrait; + + fn link(&self) -> Vec; + + fn find_linked(&self) -> Select { + let mut select = Select::new(); + for rel in self.link().into_iter().rev() { + select = select.join_rev(JoinType::InnerJoin, rel); + } + select + } +} diff --git a/src/entity/mod.rs b/src/entity/mod.rs index 6da5e1b6..c6d15052 100644 --- a/src/entity/mod.rs +++ b/src/entity/mod.rs @@ -2,6 +2,7 @@ mod active_model; mod base_entity; mod column; mod identity; +mod link; mod model; pub mod prelude; mod primary_key; @@ -11,6 +12,7 @@ pub use active_model::*; pub use base_entity::*; pub use column::*; pub use identity::*; +pub use link::*; pub use model::*; // pub use prelude::*; pub use primary_key::*; diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 7b2d7b4d..93c00596 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -30,22 +30,6 @@ where } } -pub trait Linked { - type FromEntity: EntityTrait; - - type ToEntity: EntityTrait; - - fn link(&self) -> Vec; - - fn find_linked(&self) -> Select { - let mut select = Select::new(); - for rel in self.link().into_iter().rev() { - select = select.join_rev(JoinType::InnerJoin, rel); - } - select - } -} - #[derive(Debug)] pub struct RelationDef { pub rel_type: RelationType, From 5cb1088fd9badeb5e4bb3a6abab0d65169bd59e4 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 15 Sep 2021 10:51:44 +0800 Subject: [PATCH 17/32] Update sea-query dependency --- sea-orm-codegen/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index d328724d..de38c992 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -15,7 +15,7 @@ name = "sea_orm_codegen" path = "src/lib.rs" [dependencies] -sea-query = { version = "^0.16.1", git = "https://github.com/SeaQL/sea-query.git", branch = "foreign-key-getters" } +sea-query = { version = "^0.16.2" } syn = { version = "^1", default-features = false, features = [ "derive", "parsing", From dc10caac4cb84ddd872abed5316dd079d261510a Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Wed, 15 Sep 2021 12:57:50 +0800 Subject: [PATCH 18/32] Fix sea-schema dependency --- sea-orm-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 8c9fd17e..4c23912c 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -22,7 +22,7 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", branch = "update-sea-query-version", default-features = false, features = [ +sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", default-features = false, features = [ "sqlx-mysql", "sqlx-postgres", "discovery", From 962d89524912e1c59619545b27f5346706053484 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 10:14:01 +0800 Subject: [PATCH 19/32] Add CLI verbose option --- sea-orm-cli/Cargo.toml | 5 ++++- sea-orm-cli/src/cli.rs | 8 ++++++++ sea-orm-cli/src/main.rs | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 4c23912c..0191d055 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -22,13 +22,16 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", default-features = false, features = [ +sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", branch = "log", default-features = false, features = [ + "debug-print", "sqlx-mysql", "sqlx-postgres", "discovery", "writer", ] } sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ] } +env_logger = { version = "^0.9" } +log = { version = "^0.4" } [features] default = [ "runtime-async-std-native-tls" ] diff --git a/sea-orm-cli/src/cli.rs b/sea-orm-cli/src/cli.rs index 400374c5..100c747c 100644 --- a/sea-orm-cli/src/cli.rs +++ b/sea-orm-cli/src/cli.rs @@ -62,5 +62,13 @@ pub fn build_cli() -> App<'static, 'static> { .version(env!("CARGO_PKG_VERSION")) .setting(AppSettings::VersionlessSubcommands) .subcommand(entity_subcommand) + .arg( + Arg::with_name("VERBOSE") + .long("verbose") + .short("v") + .help("Show debug messages") + .takes_value(false) + .global(true), + ) .setting(AppSettings::SubcommandRequiredElseHelp) } diff --git a/sea-orm-cli/src/main.rs b/sea-orm-cli/src/main.rs index 2f51aefb..e7041ef0 100644 --- a/sea-orm-cli/src/main.rs +++ b/sea-orm-cli/src/main.rs @@ -1,5 +1,6 @@ use clap::ArgMatches; use dotenv::dotenv; +use log::LevelFilter; use sea_orm_codegen::{EntityTransformer, OutputFile}; use std::{error::Error, fmt::Display, fs, io::Write, path::Path, process::Command}; @@ -33,6 +34,12 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box Date: Thu, 16 Sep 2021 13:11:04 +0800 Subject: [PATCH 20/32] Add & parse "ignore" macro attribute --- sea-orm-macros/src/derives/active_model.rs | 3 ++ sea-orm-macros/src/derives/entity_model.rs | 11 ++++- sea-orm-macros/src/derives/model.rs | 51 +++++++++++++++++++--- sea-orm-macros/src/lib.rs | 3 +- sea-orm-macros/src/util.rs | 26 +++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 sea-orm-macros/src/util.rs diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index 16e09f2a..4c1b909f 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -1,3 +1,4 @@ +use crate::util::field_not_ignored; use heck::CamelCase; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; @@ -16,6 +17,8 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result = fields .clone() .into_iter() diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index 66c5725f..768d3b7c 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -68,6 +68,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res let mut default_value = None; let mut default_expr = None; let mut indexed = false; + let mut ignore = false; let mut unique = false; let mut sql_type = None; // search for #[sea_orm(primary_key, auto_increment = false, column_type = "String(Some(255))", default_value = "new user", default_expr = "gen_random_uuid()", nullable, indexed, unique)] @@ -120,7 +121,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res } Meta::Path(p) => { if let Some(name) = p.get_ident() { - if name == "primary_key" { + if name == "ignore" { + ignore = true; + break; + } else if name == "primary_key" { primary_keys.push(quote! { #field_name }); primary_key_types.push(field.ty.clone()); } else if name == "nullable" { @@ -138,6 +142,11 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res } } + if ignore { + columns_enum.pop(); + continue; + } + let field_type = match sql_type { Some(t) => t, None => { diff --git a/sea-orm-macros/src/derives/model.rs b/sea-orm-macros/src/derives/model.rs index 669dbe9e..9d619991 100644 --- a/sea-orm-macros/src/derives/model.rs +++ b/sea-orm-macros/src/derives/model.rs @@ -1,8 +1,9 @@ -use crate::attributes::derive_attr; +use crate::{attributes::derive_attr, util::field_not_ignored}; use heck::CamelCase; use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned}; use std::iter::FromIterator; +use syn::Ident; enum Error { InputNotStruct, @@ -14,6 +15,7 @@ struct DeriveModel { entity_ident: syn::Ident, field_idents: Vec, ident: syn::Ident, + ignore_attrs: Vec, } impl DeriveModel { @@ -48,11 +50,17 @@ impl DeriveModel { }) .collect(); + let ignore_attrs = fields + .iter() + .map(|field| !field_not_ignored(field)) + .collect(); + Ok(DeriveModel { column_idents, entity_ident, field_idents, ident, + ignore_attrs, }) } @@ -70,23 +78,56 @@ impl DeriveModel { let ident = &self.ident; let field_idents = &self.field_idents; let column_idents = &self.column_idents; + let field_values: Vec = column_idents + .iter() + .zip(&self.ignore_attrs) + .map(|(column_ident, ignore)| { + if *ignore { + quote! { + Default::default() + } + } else { + quote! { + row.try_get(pre, sea_orm::IdenStatic::as_str(&<::Entity as sea_orm::entity::EntityTrait>::Column::#column_ident).into())? + } + } + }) + .collect(); quote!( impl sea_orm::FromQueryResult for #ident { fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> Result { Ok(Self { - #(#field_idents: row.try_get(pre, sea_orm::IdenStatic::as_str(&<::Entity as sea_orm::entity::EntityTrait>::Column::#column_idents).into())?),* + #(#field_idents: #field_values),* }) } } ) } - fn impl_model_trait(&self) -> TokenStream { + fn impl_model_trait<'a>(&'a self) -> TokenStream { let ident = &self.ident; let entity_ident = &self.entity_ident; - let field_idents = &self.field_idents; - let column_idents = &self.column_idents; + let ignore_attrs = &self.ignore_attrs; + let ignore = |(ident, ignore): (&'a Ident, &bool)| -> Option<&'a Ident> { + if *ignore { + None + } else { + Some(ident) + } + }; + let field_idents: Vec<&Ident> = self + .field_idents + .iter() + .zip(ignore_attrs) + .filter_map(ignore) + .collect(); + let column_idents: Vec<&Ident> = self + .column_idents + .iter() + .zip(ignore_attrs) + .filter_map(ignore) + .collect(); let missing_field_msg = format!("field does not exist on {}", ident); diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 879ad5eb..629c5c18 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -5,6 +5,7 @@ use syn::{parse_macro_input, DeriveInput, Error}; mod attributes; mod derives; +mod util; #[proc_macro_derive(DeriveEntity, attributes(sea_orm))] pub fn derive_entity(input: TokenStream) -> TokenStream { @@ -73,7 +74,7 @@ pub fn derive_model(input: TokenStream) -> TokenStream { .into() } -#[proc_macro_derive(DeriveActiveModel)] +#[proc_macro_derive(DeriveActiveModel, attributes(sea_orm))] pub fn derive_active_model(input: TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input); diff --git a/sea-orm-macros/src/util.rs b/sea-orm-macros/src/util.rs new file mode 100644 index 00000000..7dda1087 --- /dev/null +++ b/sea-orm-macros/src/util.rs @@ -0,0 +1,26 @@ +use syn::{punctuated::Punctuated, token::Comma, Field, Meta}; + +pub(crate) fn field_not_ignored(field: &Field) -> bool { + for attr in field.attrs.iter() { + if let Some(ident) = attr.path.get_ident() { + if ident != "sea_orm" { + continue; + } + } else { + continue; + } + + if let Ok(list) = attr.parse_args_with(Punctuated::::parse_terminated) { + for meta in list.iter() { + if let Meta::Path(path) = meta { + if let Some(name) = path.get_ident() { + if name == "ignore" { + return false; + } + } + } + } + } + } + true +} From 4e7bf8b8360f75364d5e3ea7fccd7611c44e7b52 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 13:11:26 +0800 Subject: [PATCH 21/32] Testing --- src/tests_cfg/cake_filling_price.rs | 2 ++ src/tests_cfg/filling.rs | 2 ++ tests/common/bakery_chain/baker.rs | 2 ++ tests/common/bakery_chain/bakery.rs | 2 ++ tests/common/bakery_chain/cake.rs | 2 ++ tests/common/bakery_chain/cakes_bakers.rs | 2 ++ tests/common/bakery_chain/customer.rs | 2 ++ tests/common/bakery_chain/lineitem.rs | 2 ++ tests/common/bakery_chain/order.rs | 2 ++ 9 files changed, 18 insertions(+) diff --git a/src/tests_cfg/cake_filling_price.rs b/src/tests_cfg/cake_filling_price.rs index e820ae0f..12779d14 100644 --- a/src/tests_cfg/cake_filling_price.rs +++ b/src/tests_cfg/cake_filling_price.rs @@ -19,6 +19,8 @@ pub struct Model { pub cake_id: i32, pub filling_id: i32, pub price: Decimal, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] diff --git a/src/tests_cfg/filling.rs b/src/tests_cfg/filling.rs index 433a89b8..14f7a849 100644 --- a/src/tests_cfg/filling.rs +++ b/src/tests_cfg/filling.rs @@ -9,6 +9,8 @@ pub struct Entity; pub struct Model { pub id: i32, pub name: String, + #[sea_orm(ignore)] + pub ignored_attr: i32, } // If your column names are not in snake-case, derive `DeriveCustomColumn` here. diff --git a/tests/common/bakery_chain/baker.rs b/tests/common/bakery_chain/baker.rs index ec3d3fb5..45b6c64b 100644 --- a/tests/common/bakery_chain/baker.rs +++ b/tests/common/bakery_chain/baker.rs @@ -8,6 +8,8 @@ pub struct Model { pub name: String, pub contact_details: Json, pub bakery_id: Option, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/bakery.rs b/tests/common/bakery_chain/bakery.rs index a168ad1c..5658740d 100644 --- a/tests/common/bakery_chain/bakery.rs +++ b/tests/common/bakery_chain/bakery.rs @@ -7,6 +7,8 @@ pub struct Model { pub id: i32, pub name: String, pub profit_margin: f64, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cake.rs b/tests/common/bakery_chain/cake.rs index 4730394b..6d025fe7 100644 --- a/tests/common/bakery_chain/cake.rs +++ b/tests/common/bakery_chain/cake.rs @@ -11,6 +11,8 @@ pub struct Model { pub bakery_id: Option, pub gluten_free: bool, pub serial: Uuid, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cakes_bakers.rs b/tests/common/bakery_chain/cakes_bakers.rs index 3582ada0..6a1eeb54 100644 --- a/tests/common/bakery_chain/cakes_bakers.rs +++ b/tests/common/bakery_chain/cakes_bakers.rs @@ -7,6 +7,8 @@ pub struct Model { pub cake_id: i32, #[sea_orm(primary_key)] pub baker_id: i32, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/customer.rs b/tests/common/bakery_chain/customer.rs index 31e41018..1d3563e4 100644 --- a/tests/common/bakery_chain/customer.rs +++ b/tests/common/bakery_chain/customer.rs @@ -8,6 +8,8 @@ pub struct Model { pub name: String, #[sea_orm(column_type = "Text", nullable)] pub notes: Option, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/lineitem.rs b/tests/common/bakery_chain/lineitem.rs index c2d18987..27a79fa3 100644 --- a/tests/common/bakery_chain/lineitem.rs +++ b/tests/common/bakery_chain/lineitem.rs @@ -10,6 +10,8 @@ pub struct Model { pub quantity: i32, pub order_id: i32, pub cake_id: i32, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/order.rs b/tests/common/bakery_chain/order.rs index ed6185cf..e52ba04c 100644 --- a/tests/common/bakery_chain/order.rs +++ b/tests/common/bakery_chain/order.rs @@ -10,6 +10,8 @@ pub struct Model { pub bakery_id: i32, pub customer_id: i32, pub placed_at: DateTime, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] From beca48d48e361e5b79088b416573c738bab1972a Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 14:59:48 +0800 Subject: [PATCH 22/32] Refactor --- sea-orm-macros/src/derives/active_model.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index 4c1b909f..3a96860e 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -15,9 +15,9 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result compile_error!("you can only derive DeriveActiveModel on structs"); }) } - }; - - let fields = fields.into_iter().filter(field_not_ignored); + } + .into_iter() + .filter(field_not_ignored); let field: Vec = fields .clone() From 9107c9010a45ddc1f931b5df77489b788fefc277 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Thu, 16 Sep 2021 11:47:31 +0300 Subject: [PATCH 23/32] add `into_model()` for `Statement` --- src/database/statement.rs | 71 ++++++++++++++++++++++++++++++++++++++- src/executor/select.rs | 14 ++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/database/statement.rs b/src/database/statement.rs index 12b07487..530325c4 100644 --- a/src/database/statement.rs +++ b/src/database/statement.rs @@ -1,4 +1,4 @@ -use crate::DbBackend; +use crate::{DbBackend, FromQueryResult, SelectModel, SelectorRaw}; use sea_query::{inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder}; pub use sea_query::{Value, Values}; use std::fmt; @@ -43,6 +43,75 @@ impl Statement { db_backend, } } + + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres) + /// # .append_query_results(vec![vec![ + /// # maplit::btreemap! { + /// # "name" => Into::::into("Chocolate Forest"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # maplit::btreemap! { + /// # "name" => Into::::into("New York Cheese"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # ]]) + /// # .into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult}; + /// + /// #[derive(Debug, PartialEq, FromQueryResult)] + /// struct SelectResult { + /// name: String, + /// num_of_cakes: i32, + /// } + /// + /// # let _: Result<(), DbErr> = smol::block_on(async { + /// # + /// let res: Vec = Statement::from_sql_and_values( + /// DbBackend::Postgres, + /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, + /// vec![], + /// ) + /// .into_model::() + /// .all(&db) + /// .await?; + /// + /// assert_eq!( + /// res, + /// vec![ + /// SelectResult { + /// name: "Chocolate Forest".to_owned(), + /// num_of_cakes: 1, + /// }, + /// SelectResult { + /// name: "New York Cheese".to_owned(), + /// num_of_cakes: 1, + /// }, + /// ] + /// ); + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![Transaction::from_sql_and_values( + /// DbBackend::Postgres, + /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, + /// vec![] + /// ),] + /// ); + /// ``` + pub fn into_model(self) -> SelectorRaw> + where + M: FromQueryResult, + { + SelectorRaw::>::from_statement(self) + } } impl fmt::Display for Statement { diff --git a/src/executor/select.rs b/src/executor/select.rs index ef30bb3d..961ec37b 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -263,6 +263,20 @@ impl SelectorRaw where S: SelectorTrait, { + // Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will + // return a type `M` which implement `FromQueryResult`. + // + // Helper function used by `Statment.into_model()` + pub(crate) fn from_statement(stmt: Statement) -> SelectorRaw> + where + M: FromQueryResult, + { + SelectorRaw { + stmt, + selector: SelectModel { model: PhantomData }, + } + } + /// ``` /// # #[cfg(feature = "mock")] /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; From c1e399ae1867a55b0138e482bd5774d10c79e1d0 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 18:29:30 +0800 Subject: [PATCH 24/32] Add example of debug log support --- examples/tokio/Cargo.toml | 2 ++ examples/tokio/src/main.rs | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/tokio/Cargo.toml b/examples/tokio/Cargo.toml index 173e9906..b1124aad 100644 --- a/examples/tokio/Cargo.toml +++ b/examples/tokio/Cargo.toml @@ -10,3 +10,5 @@ publish = false [dependencies] sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-tokio-native-tls" ] } tokio = { version = "1", features = ["full"] } +env_logger = { version = "^0.9" } +log = { version = "^0.4" } diff --git a/examples/tokio/src/main.rs b/examples/tokio/src/main.rs index dd81b4ab..14a76086 100644 --- a/examples/tokio/src/main.rs +++ b/examples/tokio/src/main.rs @@ -3,7 +3,12 @@ use sea_orm::*; #[tokio::main] pub async fn main() { - let db = Database::connect("sql://sea:sea@localhost/bakery") + env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .is_test(true) + .init(); + + let db = Database::connect("mysql://sea:sea@localhost/bakery") .await .unwrap(); From e71a74b0c1cf4bc391733d35a1e8c2ac12269a04 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Thu, 16 Sep 2021 18:06:02 +0300 Subject: [PATCH 25/32] Improve working with raw SQL - Add `find_by_statement` to `T: FromQueryResult` - Add `SelectorRaw::from_statement` constructor --- src/database/statement.rs | 71 +------------------------------------ src/entity/model.rs | 74 ++++++++++++++++++++++++++++++++++++++- src/entity/prelude.rs | 5 +-- src/executor/select.rs | 8 ++--- 4 files changed, 80 insertions(+), 78 deletions(-) diff --git a/src/database/statement.rs b/src/database/statement.rs index 530325c4..12b07487 100644 --- a/src/database/statement.rs +++ b/src/database/statement.rs @@ -1,4 +1,4 @@ -use crate::{DbBackend, FromQueryResult, SelectModel, SelectorRaw}; +use crate::DbBackend; use sea_query::{inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder}; pub use sea_query::{Value, Values}; use std::fmt; @@ -43,75 +43,6 @@ impl Statement { db_backend, } } - - /// ``` - /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; - /// # - /// # let db = MockDatabase::new(DbBackend::Postgres) - /// # .append_query_results(vec![vec![ - /// # maplit::btreemap! { - /// # "name" => Into::::into("Chocolate Forest"), - /// # "num_of_cakes" => Into::::into(1), - /// # }, - /// # maplit::btreemap! { - /// # "name" => Into::::into("New York Cheese"), - /// # "num_of_cakes" => Into::::into(1), - /// # }, - /// # ]]) - /// # .into_connection(); - /// # - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult}; - /// - /// #[derive(Debug, PartialEq, FromQueryResult)] - /// struct SelectResult { - /// name: String, - /// num_of_cakes: i32, - /// } - /// - /// # let _: Result<(), DbErr> = smol::block_on(async { - /// # - /// let res: Vec = Statement::from_sql_and_values( - /// DbBackend::Postgres, - /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, - /// vec![], - /// ) - /// .into_model::() - /// .all(&db) - /// .await?; - /// - /// assert_eq!( - /// res, - /// vec![ - /// SelectResult { - /// name: "Chocolate Forest".to_owned(), - /// num_of_cakes: 1, - /// }, - /// SelectResult { - /// name: "New York Cheese".to_owned(), - /// num_of_cakes: 1, - /// }, - /// ] - /// ); - /// # - /// # Ok(()) - /// # }); - /// - /// assert_eq!( - /// db.into_transaction_log(), - /// vec![Transaction::from_sql_and_values( - /// DbBackend::Postgres, - /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, - /// vec![] - /// ),] - /// ); - /// ``` - pub fn into_model(self) -> SelectorRaw> - where - M: FromQueryResult, - { - SelectorRaw::>::from_statement(self) - } } impl fmt::Display for Statement { diff --git a/src/entity/model.rs b/src/entity/model.rs index 25a43753..25b46719 100644 --- a/src/entity/model.rs +++ b/src/entity/model.rs @@ -1,4 +1,7 @@ -use crate::{DbErr, EntityTrait, Linked, QueryFilter, QueryResult, Related, Select}; +use crate::{ + DbErr, EntityTrait, Linked, QueryFilter, QueryResult, Related, Select, SelectModel, + SelectorRaw, Statement, +}; pub use sea_query::Value; use std::fmt::Debug; @@ -37,3 +40,72 @@ pub trait FromQueryResult { Ok(Self::from_query_result(res, pre).ok()) } } + +pub trait FromQueryResultExt: FromQueryResult + Sized { + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres) + /// # .append_query_results(vec![vec![ + /// # maplit::btreemap! { + /// # "name" => Into::::into("Chocolate Forest"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # maplit::btreemap! { + /// # "name" => Into::::into("New York Cheese"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # ]]) + /// # .into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult}; + /// + /// #[derive(Debug, PartialEq, FromQueryResult)] + /// struct SelectResult { + /// name: String, + /// num_of_cakes: i32, + /// } + /// + /// # let _: Result<(), DbErr> = smol::block_on(async { + /// # + /// let res: Vec = SelectResult::find_by_statement(Statement::from_sql_and_values( + /// DbBackend::Postgres, + /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, + /// vec![], + /// )) + /// .all(&db) + /// .await?; + /// + /// assert_eq!( + /// res, + /// vec![ + /// SelectResult { + /// name: "Chocolate Forest".to_owned(), + /// num_of_cakes: 1, + /// }, + /// SelectResult { + /// name: "New York Cheese".to_owned(), + /// num_of_cakes: 1, + /// }, + /// ] + /// ); + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![Transaction::from_sql_and_values( + /// DbBackend::Postgres, + /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, + /// vec![] + /// ),] + /// ); + /// ``` + fn find_by_statement(stmt: Statement) -> SelectorRaw> { + SelectorRaw::>::from_statement(stmt) + } +} + +impl FromQueryResultExt for T {} diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 8d87a4b2..22cfeeb0 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -2,8 +2,9 @@ pub use crate::{ error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait, - EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, - PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value, + EnumIter, ForeignKeyAction, FromQueryResultExt, Iden, IdenStatic, Linked, ModelTrait, + PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, + RelationTrait, Select, Value, }; #[cfg(feature = "with-json")] diff --git a/src/executor/select.rs b/src/executor/select.rs index 961ec37b..959091c0 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -263,11 +263,9 @@ impl SelectorRaw where S: SelectorTrait, { - // Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will - // return a type `M` which implement `FromQueryResult`. - // - // Helper function used by `Statment.into_model()` - pub(crate) fn from_statement(stmt: Statement) -> SelectorRaw> + /// Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will + /// return a type `M` which implement `FromQueryResult`. + pub fn from_statement(stmt: Statement) -> SelectorRaw> where M: FromQueryResult, { From 2b36ab0ae003389b22bc5df2a11cfb2438af420d Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 17 Sep 2021 12:23:06 +0800 Subject: [PATCH 26/32] Update Cargo.toml --- sea-orm-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 0191d055..0392f51e 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -22,7 +22,7 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", branch = "log", default-features = false, features = [ +sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", default-features = false, features = [ "debug-print", "sqlx-mysql", "sqlx-postgres", From 51a690ba995ce2c7214f84e57a479de62f81f3f4 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 17 Sep 2021 12:26:31 +0800 Subject: [PATCH 27/32] Update Cargo.toml --- sea-orm-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 0392f51e..484b6efb 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -22,7 +22,7 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm-codegen = { version = "^0.2.0", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.7", git = "https://github.com/SeaQL/sea-schema.git", default-features = false, features = [ +sea-schema = { version = "^0.2.8", git = "https://github.com/SeaQL/sea-schema.git", default-features = false, features = [ "debug-print", "sqlx-mysql", "sqlx-postgres", From 2e1371537abb9c836f550cf2a38054a7010bdd01 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 17 Sep 2021 15:03:23 +0800 Subject: [PATCH 28/32] Merge FromQueryResultExt into FromQueryResult --- src/entity/model.rs | 15 +++------------ src/entity/prelude.rs | 5 ++--- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/entity/model.rs b/src/entity/model.rs index 25b46719..c6129ad7 100644 --- a/src/entity/model.rs +++ b/src/entity/model.rs @@ -28,20 +28,13 @@ pub trait ModelTrait: Clone + Send + Debug { } } -pub trait FromQueryResult { - fn from_query_result(res: &QueryResult, pre: &str) -> Result - where - Self: Sized; +pub trait FromQueryResult: Sized { + fn from_query_result(res: &QueryResult, pre: &str) -> Result; - fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result, DbErr> - where - Self: Sized, - { + fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result, DbErr> { Ok(Self::from_query_result(res, pre).ok()) } -} -pub trait FromQueryResultExt: FromQueryResult + Sized { /// ``` /// # #[cfg(feature = "mock")] /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; @@ -107,5 +100,3 @@ pub trait FromQueryResultExt: FromQueryResult + Sized { SelectorRaw::>::from_statement(stmt) } } - -impl FromQueryResultExt for T {} diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 22cfeeb0..8d87a4b2 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -2,9 +2,8 @@ pub use crate::{ error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait, - EnumIter, ForeignKeyAction, FromQueryResultExt, Iden, IdenStatic, Linked, ModelTrait, - PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, - RelationTrait, Select, Value, + EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, + PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value, }; #[cfg(feature = "with-json")] From 6e7e2a59d3c86a32afcc9b7c72e557f51d07b094 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 17 Sep 2021 15:16:30 +0800 Subject: [PATCH 29/32] cargo fmt --- src/entity/link.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entity/link.rs b/src/entity/link.rs index 712adaa6..97c9af1b 100644 --- a/src/entity/link.rs +++ b/src/entity/link.rs @@ -1,5 +1,5 @@ -use crate::{EntityTrait, RelationDef, QuerySelect, Select}; -use sea_query::{JoinType}; +use crate::{EntityTrait, QuerySelect, RelationDef, Select}; +use sea_query::JoinType; pub type LinkDef = RelationDef; From a280a227d88c54619d2d52edf107a0fe522e132e Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 17 Sep 2021 16:03:37 +0800 Subject: [PATCH 30/32] TODO --- src/executor/insert.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/executor/insert.rs b/src/executor/insert.rs index 90065675..1f4936ba 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -34,6 +34,7 @@ where where A: 'a, { + // TODO: extract primary key's value from query // so that self is dropped before entering await let mut query = self.query; #[cfg(feature = "sqlx-postgres")] @@ -48,6 +49,7 @@ where } } Inserter::::new(query).exec(db) + // TODO: return primary key if extracted before, otherwise use InsertResult } } From 5fe8c7c9c4047102a25024b1524fcacc45a57ef1 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 17 Sep 2021 17:08:55 +0800 Subject: [PATCH 31/32] Revert adding `#[sea_orm(ignore)]` to tests entities --- tests/common/bakery_chain/baker.rs | 2 -- tests/common/bakery_chain/bakery.rs | 2 -- tests/common/bakery_chain/cake.rs | 2 -- tests/common/bakery_chain/cakes_bakers.rs | 2 -- tests/common/bakery_chain/customer.rs | 2 -- tests/common/bakery_chain/lineitem.rs | 2 -- tests/common/bakery_chain/order.rs | 2 -- 7 files changed, 14 deletions(-) diff --git a/tests/common/bakery_chain/baker.rs b/tests/common/bakery_chain/baker.rs index 45b6c64b..ec3d3fb5 100644 --- a/tests/common/bakery_chain/baker.rs +++ b/tests/common/bakery_chain/baker.rs @@ -8,8 +8,6 @@ pub struct Model { pub name: String, pub contact_details: Json, pub bakery_id: Option, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/bakery.rs b/tests/common/bakery_chain/bakery.rs index 5658740d..a168ad1c 100644 --- a/tests/common/bakery_chain/bakery.rs +++ b/tests/common/bakery_chain/bakery.rs @@ -7,8 +7,6 @@ pub struct Model { pub id: i32, pub name: String, pub profit_margin: f64, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cake.rs b/tests/common/bakery_chain/cake.rs index 6d025fe7..4730394b 100644 --- a/tests/common/bakery_chain/cake.rs +++ b/tests/common/bakery_chain/cake.rs @@ -11,8 +11,6 @@ pub struct Model { pub bakery_id: Option, pub gluten_free: bool, pub serial: Uuid, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cakes_bakers.rs b/tests/common/bakery_chain/cakes_bakers.rs index 6a1eeb54..3582ada0 100644 --- a/tests/common/bakery_chain/cakes_bakers.rs +++ b/tests/common/bakery_chain/cakes_bakers.rs @@ -7,8 +7,6 @@ pub struct Model { pub cake_id: i32, #[sea_orm(primary_key)] pub baker_id: i32, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/customer.rs b/tests/common/bakery_chain/customer.rs index 1d3563e4..31e41018 100644 --- a/tests/common/bakery_chain/customer.rs +++ b/tests/common/bakery_chain/customer.rs @@ -8,8 +8,6 @@ pub struct Model { pub name: String, #[sea_orm(column_type = "Text", nullable)] pub notes: Option, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/lineitem.rs b/tests/common/bakery_chain/lineitem.rs index 27a79fa3..c2d18987 100644 --- a/tests/common/bakery_chain/lineitem.rs +++ b/tests/common/bakery_chain/lineitem.rs @@ -10,8 +10,6 @@ pub struct Model { pub quantity: i32, pub order_id: i32, pub cake_id: i32, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/order.rs b/tests/common/bakery_chain/order.rs index e52ba04c..ed6185cf 100644 --- a/tests/common/bakery_chain/order.rs +++ b/tests/common/bakery_chain/order.rs @@ -10,8 +10,6 @@ pub struct Model { pub bakery_id: i32, pub customer_id: i32, pub placed_at: DateTime, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] From a45c44cfc5e1c0741967fb2e40aa2648bea92e58 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 17 Sep 2021 11:23:32 +0800 Subject: [PATCH 32/32] Add cake_expanded entity file for docs demo --- src/tests_cfg/cake_expanded.rs | 94 ++++++++++++++++++++++++++++++++++ src/tests_cfg/fruit.rs | 12 +++++ src/tests_cfg/mod.rs | 2 + 3 files changed, 108 insertions(+) create mode 100644 src/tests_cfg/cake_expanded.rs diff --git a/src/tests_cfg/cake_expanded.rs b/src/tests_cfg/cake_expanded.rs new file mode 100644 index 00000000..0eeb0738 --- /dev/null +++ b/src/tests_cfg/cake_expanded.rs @@ -0,0 +1,94 @@ +use crate as sea_orm; +use crate::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "cake" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub name: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Name, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + type ValueType = i32; + + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Fruit, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Name => ColumnType::String(None).def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Fruit => Entity::has_many(super::fruit::Entity).into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Fruit.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::cake_filling::Relation::Filling.def() + } + + fn via() -> Option { + Some(super::cake_filling::Relation::Cake.def().rev()) + } +} + +#[derive(Debug)] +pub struct CakeToFilling; + +impl Linked for CakeToFilling { + type FromEntity = Entity; + + type ToEntity = super::filling::Entity; + + fn link(&self) -> Vec { + vec![ + super::cake_filling::Relation::Cake.def().rev(), + super::cake_filling::Relation::Filling.def(), + ] + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/fruit.rs b/src/tests_cfg/fruit.rs index 390f502a..166820a2 100644 --- a/src/tests_cfg/fruit.rs +++ b/src/tests_cfg/fruit.rs @@ -18,6 +18,12 @@ pub enum Relation { to = "super::cake::Column::Id" )] Cake, + #[sea_orm( + belongs_to = "super::cake_expanded::Entity", + from = "Column::CakeId", + to = "super::cake_expanded::Column::Id" + )] + CakeExpanded, } impl Related for Entity { @@ -26,4 +32,10 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::CakeExpanded.def() + } +} + impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/mod.rs b/src/tests_cfg/mod.rs index afb9e115..81d553ac 100644 --- a/src/tests_cfg/mod.rs +++ b/src/tests_cfg/mod.rs @@ -1,12 +1,14 @@ //! Configurations for test cases and examples. Not intended for actual use. pub mod cake; +pub mod cake_expanded; pub mod cake_filling; pub mod cake_filling_price; pub mod filling; pub mod fruit; pub use cake::Entity as Cake; +pub use cake_expanded::Entity as CakeExpanded; pub use cake_filling::Entity as CakeFilling; pub use cake_filling_price::Entity as CakeFillingPrice; pub use filling::Entity as Filling;