diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index 7357a9eea..45d3801dd 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -26,3 +26,4 @@ tracing = { version = "0.1", default-features = false, features = ["log"] } [dev-dependencies] pretty_assertions = { version = "0.7" } +sea-orm = { path = "../", default-features = false, features = ["macros"] } diff --git a/sea-orm-codegen/rustfmt.toml b/sea-orm-codegen/rustfmt.toml index d7f6da657..8b1ff05b1 100644 --- a/sea-orm-codegen/rustfmt.toml +++ b/sea-orm-codegen/rustfmt.toml @@ -1,4 +1,5 @@ ignore = [ "tests/compact/*.rs", "tests/expanded/*.rs", + "tests_cfg", ] \ No newline at end of file diff --git a/sea-orm-codegen/src/entity/transformer.rs b/sea-orm-codegen/src/entity/transformer.rs index 53006cbe0..06a23b520 100644 --- a/sea-orm-codegen/src/entity/transformer.rs +++ b/sea-orm-codegen/src/entity/transformer.rs @@ -3,7 +3,7 @@ use crate::{ PrimaryKey, Relation, RelationType, }; use sea_query::{ColumnSpec, TableCreateStatement}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; #[derive(Clone, Debug)] pub struct EntityTransformer; @@ -12,7 +12,6 @@ impl EntityTransformer { pub fn transform(table_create_stmts: Vec) -> Result { let mut enums: BTreeMap = BTreeMap::new(); let mut inverse_relations: BTreeMap> = BTreeMap::new(); - let mut conjunct_relations: BTreeMap> = BTreeMap::new(); let mut entities = BTreeMap::new(); for table_create in table_create_stmts.into_iter() { let table_name = match table_create.get_table_name() { @@ -125,7 +124,7 @@ impl EntityTransformer { primary_keys, }; entities.insert(table_name.clone(), entity.clone()); - for (i, mut rel) in relations.into_iter().enumerate() { + for mut rel in relations.into_iter() { // This will produce a duplicated relation if rel.self_referencing { continue; @@ -135,51 +134,33 @@ impl EntityTransformer { if rel.num_suffix > 0 { continue; } - let is_conjunct_relation = - entity.relations.len() == 2 && entity.primary_keys.len() == 2; - match is_conjunct_relation { - true => { - let another_rel = entity.relations.get((i == 0) as usize).unwrap(); - let conjunct_relation = ConjunctRelation { - via: table_name.clone(), - to: another_rel.ref_table.clone(), - }; - if let Some(vec) = conjunct_relations.get_mut(&rel.ref_table) { - vec.push(conjunct_relation); - } else { - conjunct_relations.insert(rel.ref_table, vec![conjunct_relation]); - } - } - false => { - let ref_table = rel.ref_table; - let mut unique = true; - for column in rel.columns.iter() { - if !entity - .columns - .iter() - .filter(|col| col.unique) - .any(|col| col.name.as_str() == column) - { - unique = false; - break; - } - } - let rel_type = if unique { - RelationType::HasOne - } else { - RelationType::HasMany - }; - rel.rel_type = rel_type; - rel.ref_table = table_name.clone(); - rel.columns = Vec::new(); - rel.ref_columns = Vec::new(); - if let Some(vec) = inverse_relations.get_mut(&ref_table) { - vec.push(rel); - } else { - inverse_relations.insert(ref_table, vec![rel]); - } + let ref_table = rel.ref_table; + let mut unique = true; + for column in rel.columns.iter() { + if !entity + .columns + .iter() + .filter(|col| col.unique) + .any(|col| col.name.as_str() == column) + { + unique = false; + break; } } + let rel_type = if unique { + RelationType::HasOne + } else { + RelationType::HasMany + }; + rel.rel_type = rel_type; + rel.ref_table = table_name.clone(); + rel.columns = Vec::new(); + rel.ref_columns = Vec::new(); + if let Some(vec) = inverse_relations.get_mut(&ref_table) { + vec.push(rel); + } else { + inverse_relations.insert(ref_table, vec![rel]); + } } } for (tbl_name, relations) in inverse_relations.into_iter() { @@ -195,26 +176,64 @@ impl EntityTransformer { } } } - for (tbl_name, mut conjunct_relations) in conjunct_relations.into_iter() { - if let Some(entity) = entities.get_mut(&tbl_name) { - for relation in entity.relations.iter_mut() { - // Skip `impl Related ... { fn to() ... }` implementation block, - // if the same related entity is being referenced by a conjunct relation - if conjunct_relations - .iter() - .any(|conjunct_relation| conjunct_relation.to == relation.ref_table) - { - relation.impl_related = false; + for table_name in entities.clone().keys() { + let relations = match entities.get(table_name) { + Some(entity) => { + let is_conjunct_relation = + entity.relations.len() == 2 && entity.primary_keys.len() == 2; + if !is_conjunct_relation { + continue; } + entity.relations.clone() + } + None => unreachable!(), + }; + for (i, rel) in relations.iter().enumerate() { + let another_rel = relations.get((i == 0) as usize).unwrap(); + if let Some(entity) = entities.get_mut(&rel.ref_table) { + let conjunct_relation = ConjunctRelation { + via: table_name.clone(), + to: another_rel.ref_table.clone(), + }; + entity.conjunct_relations.push(conjunct_relation); } - entity.conjunct_relations.append(&mut conjunct_relations); } } Ok(EntityWriter { entities: entities .into_values() .map(|mut v| { + // Filter duplicated conjunct relations + let duplicated_to: Vec<_> = v + .conjunct_relations + .iter() + .fold(HashMap::new(), |mut acc, conjunct_relation| { + acc.entry(conjunct_relation.to.clone()) + .and_modify(|c| *c += 1) + .or_insert(1); + acc + }) + .into_iter() + .filter(|(_, v)| v > &1) + .map(|(k, _)| k) + .collect(); + v.conjunct_relations + .retain(|conjunct_relation| !duplicated_to.contains(&conjunct_relation.to)); + + // Skip `impl Related ... { fn to() ... }` implementation block, + // if the same related entity is being referenced by a conjunct relation + v.relations.iter_mut().for_each(|relation| { + if v.conjunct_relations + .iter() + .any(|conjunct_relation| conjunct_relation.to == relation.ref_table) + { + relation.impl_related = false; + } + }); + + // Sort relation vectors v.relations.sort_by(|a, b| a.ref_table.cmp(&b.ref_table)); + v.conjunct_relations.sort_by(|a, b| a.to.cmp(&b.to)); v }) .collect(), @@ -222,3 +241,179 @@ impl EntityTransformer { }) } } + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + use proc_macro2::TokenStream; + use sea_orm::{DbBackend, Schema}; + use std::{ + error::Error, + io::{self, BufRead, BufReader}, + }; + + #[test] + fn duplicated_many_to_many_paths() -> Result<(), Box> { + use crate::tests_cfg::duplicated_many_to_many_paths::*; + let schema = Schema::new(DbBackend::Postgres); + + validate_compact_entities( + vec![ + schema.create_table_from_entity(bills::Entity), + schema.create_table_from_entity(users::Entity), + schema.create_table_from_entity(users_saved_bills::Entity), + schema.create_table_from_entity(users_votes::Entity), + ], + vec![ + ( + "bills", + include_str!("../tests_cfg/duplicated_many_to_many_paths/bills.rs"), + ), + ( + "users", + include_str!("../tests_cfg/duplicated_many_to_many_paths/users.rs"), + ), + ( + "users_saved_bills", + include_str!("../tests_cfg/duplicated_many_to_many_paths/users_saved_bills.rs"), + ), + ( + "users_votes", + include_str!("../tests_cfg/duplicated_many_to_many_paths/users_votes.rs"), + ), + ], + ) + } + + #[test] + fn many_to_many() -> Result<(), Box> { + use crate::tests_cfg::many_to_many::*; + let schema = Schema::new(DbBackend::Postgres); + + validate_compact_entities( + vec![ + schema.create_table_from_entity(bills::Entity), + schema.create_table_from_entity(users::Entity), + schema.create_table_from_entity(users_votes::Entity), + ], + vec![ + ("bills", include_str!("../tests_cfg/many_to_many/bills.rs")), + ("users", include_str!("../tests_cfg/many_to_many/users.rs")), + ( + "users_votes", + include_str!("../tests_cfg/many_to_many/users_votes.rs"), + ), + ], + ) + } + + #[test] + fn many_to_many_multiple() -> Result<(), Box> { + use crate::tests_cfg::many_to_many_multiple::*; + let schema = Schema::new(DbBackend::Postgres); + + validate_compact_entities( + vec![ + schema.create_table_from_entity(bills::Entity), + schema.create_table_from_entity(users::Entity), + schema.create_table_from_entity(users_votes::Entity), + ], + vec![ + ( + "bills", + include_str!("../tests_cfg/many_to_many_multiple/bills.rs"), + ), + ( + "users", + include_str!("../tests_cfg/many_to_many_multiple/users.rs"), + ), + ( + "users_votes", + include_str!("../tests_cfg/many_to_many_multiple/users_votes.rs"), + ), + ], + ) + } + + #[test] + fn self_referencing() -> Result<(), Box> { + use crate::tests_cfg::self_referencing::*; + let schema = Schema::new(DbBackend::Postgres); + + validate_compact_entities( + vec![ + schema.create_table_from_entity(bills::Entity), + schema.create_table_from_entity(users::Entity), + ], + vec![ + ( + "bills", + include_str!("../tests_cfg/self_referencing/bills.rs"), + ), + ( + "users", + include_str!("../tests_cfg/self_referencing/users.rs"), + ), + ], + ) + } + + fn validate_compact_entities( + table_create_stmts: Vec, + files: Vec<(&str, &str)>, + ) -> Result<(), Box> { + let entities: HashMap<_, _> = EntityTransformer::transform(table_create_stmts)? + .entities + .into_iter() + .map(|entity| (entity.table_name.clone(), entity)) + .collect(); + + for (entity_name, file_content) in files { + let entity = entities + .get(entity_name) + .expect("Forget to add entity to the list"); + + assert_eq!( + parse_from_file(file_content.as_bytes())?.to_string(), + EntityWriter::gen_compact_code_blocks( + entity, + &crate::WithSerde::None, + &crate::DateTimeCrate::Chrono, + &None, + false, + false, + &Default::default(), + &Default::default(), + ) + .into_iter() + .skip(1) + .fold(TokenStream::new(), |mut acc, tok| { + acc.extend(tok); + acc + }) + .to_string() + ); + } + + Ok(()) + } + + fn parse_from_file(inner: R) -> io::Result + where + R: io::Read, + { + let mut reader = BufReader::new(inner); + 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(""); + Ok(content.parse().unwrap()) + } +} diff --git a/sea-orm-codegen/src/lib.rs b/sea-orm-codegen/src/lib.rs index 5e637de19..1cd62ade4 100644 --- a/sea-orm-codegen/src/lib.rs +++ b/sea-orm-codegen/src/lib.rs @@ -4,3 +4,6 @@ mod util; pub use entity::*; pub use error::*; + +#[cfg(test)] +mod tests_cfg; diff --git a/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/bills.rs b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/bills.rs new file mode 100644 index 000000000..a3a6911b9 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/bills.rs @@ -0,0 +1,45 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "bills")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub user_id: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "NoAction", + on_delete = "NoAction", + )] + Users, + #[sea_orm(has_many = "super::users_saved_bills::Entity")] + UsersSavedBills, + #[sea_orm(has_many = "super::users_votes::Entity")] + UsersVotes, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::UsersSavedBills.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::UsersVotes.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/mod.rs b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/mod.rs new file mode 100644 index 000000000..a9c69a25f --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/mod.rs @@ -0,0 +1,6 @@ +pub mod prelude; + +pub mod bills; +pub mod users; +pub mod users_saved_bills; +pub mod users_votes; diff --git a/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/prelude.rs b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/prelude.rs new file mode 100644 index 000000000..c18dfee05 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/prelude.rs @@ -0,0 +1,4 @@ +pub use super::bills::Entity as Bills; +pub use super::users::Entity as Users; +pub use super::users_saved_bills::Entity as UsersSavedBills; +pub use super::users_votes::Entity as UsersVotes; diff --git a/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users.rs b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users.rs new file mode 100644 index 000000000..50765913e --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users.rs @@ -0,0 +1,40 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(column_type = "Text")] + pub email: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::bills::Entity")] + Bills, + #[sea_orm(has_many = "super::users_saved_bills::Entity")] + UsersSavedBills, + #[sea_orm(has_many = "super::users_votes::Entity")] + UsersVotes, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bills.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::UsersSavedBills.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::UsersVotes.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users_saved_bills.rs b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users_saved_bills.rs new file mode 100644 index 000000000..4ef0281cd --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users_saved_bills.rs @@ -0,0 +1,44 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users_saved_bills")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub user_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub bill_id: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::bills::Entity", + from = "Column::BillId", + to = "super::bills::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Bills, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Users, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bills.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users_votes.rs b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users_votes.rs new file mode 100644 index 000000000..a04ad7fa7 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/duplicated_many_to_many_paths/users_votes.rs @@ -0,0 +1,45 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users_votes")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub user_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub bill_id: i32, + pub vote: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::bills::Entity", + from = "Column::BillId", + to = "super::bills::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Bills, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Users, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bills.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many/bills.rs b/sea-orm-codegen/src/tests_cfg/many_to_many/bills.rs new file mode 100644 index 000000000..5a3acef9c --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many/bills.rs @@ -0,0 +1,41 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "bills")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub user_id: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "NoAction", + on_delete = "NoAction", + )] + Users, + #[sea_orm(has_many = "super::users_votes::Entity")] + UsersVotes, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::UsersVotes.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::users_votes::Relation::Users.def() + } + + fn via() -> Option { + Some(super::users_votes::Relation::Bills.def().rev()) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many/mod.rs b/sea-orm-codegen/src/tests_cfg/many_to_many/mod.rs new file mode 100644 index 000000000..9cdde6457 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many/mod.rs @@ -0,0 +1,5 @@ +pub mod prelude; + +pub mod bills; +pub mod users; +pub mod users_votes; diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many/prelude.rs b/sea-orm-codegen/src/tests_cfg/many_to_many/prelude.rs new file mode 100644 index 000000000..2dc89e5fb --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many/prelude.rs @@ -0,0 +1,3 @@ +pub use super::bills::Entity as Bills; +pub use super::users::Entity as Users; +pub use super::users_votes::Entity as UsersVotes; diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many/users.rs b/sea-orm-codegen/src/tests_cfg/many_to_many/users.rs new file mode 100644 index 000000000..3afd1cd51 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many/users.rs @@ -0,0 +1,36 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(column_type = "Text")] + pub email: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::bills::Entity")] + Bills, + #[sea_orm(has_many = "super::users_votes::Entity")] + UsersVotes, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::UsersVotes.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + super::users_votes::Relation::Bills.def() + } + + fn via() -> Option { + Some(super::users_votes::Relation::Users.def().rev()) + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many/users_votes.rs b/sea-orm-codegen/src/tests_cfg/many_to_many/users_votes.rs new file mode 100644 index 000000000..a04ad7fa7 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many/users_votes.rs @@ -0,0 +1,45 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users_votes")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub user_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub bill_id: i32, + pub vote: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::bills::Entity", + from = "Column::BillId", + to = "super::bills::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Bills, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "Cascade", + on_delete = "Cascade", + )] + Users, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bills.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/bills.rs b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/bills.rs new file mode 100644 index 000000000..5094e5885 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/bills.rs @@ -0,0 +1,29 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "bills")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub user_id: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + on_update = "NoAction", + on_delete = "NoAction", + )] + Users, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Users.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/mod.rs b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/mod.rs new file mode 100644 index 000000000..9cdde6457 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/mod.rs @@ -0,0 +1,5 @@ +pub mod prelude; + +pub mod bills; +pub mod users; +pub mod users_votes; diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/prelude.rs b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/prelude.rs new file mode 100644 index 000000000..2dc89e5fb --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/prelude.rs @@ -0,0 +1,3 @@ +pub use super::bills::Entity as Bills; +pub use super::users::Entity as Users; +pub use super::users_votes::Entity as UsersVotes; diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/users.rs b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/users.rs new file mode 100644 index 000000000..99189cea4 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/users.rs @@ -0,0 +1,24 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(column_type = "Text")] + pub email: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::bills::Entity")] + Bills, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Bills.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/users_votes.rs b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/users_votes.rs new file mode 100644 index 000000000..87187f4c0 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/many_to_many_multiple/users_votes.rs @@ -0,0 +1,43 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users_votes")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub user_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub bill_id: i32, + pub user_idd: Option , + pub bill_idd: Option , + pub vote: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::bills::Entity", + from = "Column::BillIdd", + to = "super::bills::Column::Id", + )] + Bills2, + #[sea_orm( + belongs_to = "super::bills::Entity", + from = "Column::BillId", + to = "super::bills::Column::Id", + )] + Bills1, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserIdd", + to = "super::users::Column::Id", + )] + Users2, + #[sea_orm( + belongs_to = "super::users::Entity", + from = "Column::UserId", + to = "super::users::Column::Id", + )] + Users1, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/mod.rs b/sea-orm-codegen/src/tests_cfg/mod.rs new file mode 100644 index 000000000..8032c7601 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/mod.rs @@ -0,0 +1,4 @@ +pub mod duplicated_many_to_many_paths; +pub mod many_to_many; +pub mod many_to_many_multiple; +pub mod self_referencing; diff --git a/sea-orm-codegen/src/tests_cfg/self_referencing/bills.rs b/sea-orm-codegen/src/tests_cfg/self_referencing/bills.rs new file mode 100644 index 000000000..583655f67 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/self_referencing/bills.rs @@ -0,0 +1,21 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "bills")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub self_id: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "Entity", + from = "Column::SelfId", + to = "Column::Id", + )] + SelfRef, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/sea-orm-codegen/src/tests_cfg/self_referencing/mod.rs b/sea-orm-codegen/src/tests_cfg/self_referencing/mod.rs new file mode 100644 index 000000000..27afd50b7 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/self_referencing/mod.rs @@ -0,0 +1,4 @@ +pub mod prelude; + +pub mod bills; +pub mod users; diff --git a/sea-orm-codegen/src/tests_cfg/self_referencing/prelude.rs b/sea-orm-codegen/src/tests_cfg/self_referencing/prelude.rs new file mode 100644 index 000000000..1ca914b96 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/self_referencing/prelude.rs @@ -0,0 +1,2 @@ +pub use super::bills::Entity as Bills; +pub use super::users::Entity as Users; diff --git a/sea-orm-codegen/src/tests_cfg/self_referencing/users.rs b/sea-orm-codegen/src/tests_cfg/self_referencing/users.rs new file mode 100644 index 000000000..b54f3e5e2 --- /dev/null +++ b/sea-orm-codegen/src/tests_cfg/self_referencing/users.rs @@ -0,0 +1,28 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "users")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub self_id: Option , + pub self_idd: Option , +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "Entity", + from = "Column::SelfId", + to = "Column::Id", + )] + SelfRef2, + #[sea_orm( + belongs_to = "Entity", + from = "Column::SelfIdd", + to = "Column::Id", + )] + SelfRef1, +} + +impl ActiveModelBehavior for ActiveModel {}