Use belongs_to, has_one and has_many

This commit is contained in:
Billy Chan 2021-06-22 23:42:10 +08:00
parent 83e4859776
commit 9a25bb9c36
No known key found for this signature in database
GPG Key ID: A2D690CAC7DF3CC7
8 changed files with 67 additions and 32 deletions

View File

@ -53,14 +53,8 @@ impl ColumnTrait for Column {
impl RelationTrait for Relation { impl RelationTrait for Relation {
fn def(&self) -> RelationDef { fn def(&self) -> RelationDef {
match self { match self {
Self::CakeFilling => Entity::has_many(super::cake_filling::Entity) Self::CakeFilling => Entity::has_many(super::cake_filling::Entity).into(),
.from(Column::Id) Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
.to(super::cake_filling::Column::CakeId)
.into(),
Self::Fruit => Entity::has_many(super::fruit::Entity)
.from(Column::Id)
.to(super::fruit::Column::CakeId)
.into(),
} }
} }
} }

View File

@ -54,11 +54,11 @@ impl ColumnTrait for Column {
impl RelationTrait for Relation { impl RelationTrait for Relation {
fn def(&self) -> RelationDef { fn def(&self) -> RelationDef {
match self { match self {
Self::Cake => Entity::has_one(super::cake::Entity) Self::Cake => Entity::belongs_to(super::cake::Entity)
.from(Column::CakeId) .from(Column::CakeId)
.to(super::cake::Column::Id) .to(super::cake::Column::Id)
.into(), .into(),
Self::Filling => Entity::has_one(super::filling::Entity) Self::Filling => Entity::belongs_to(super::filling::Entity)
.from(Column::FillingId) .from(Column::FillingId)
.to(super::filling::Column::Id) .to(super::filling::Column::Id)
.into(), .into(),

View File

@ -52,10 +52,7 @@ impl ColumnTrait for Column {
impl RelationTrait for Relation { impl RelationTrait for Relation {
fn def(&self) -> RelationDef { fn def(&self) -> RelationDef {
match self { match self {
Self::CakeFilling => Entity::has_many(super::cake_filling::Entity) Self::CakeFilling => Entity::has_many(super::cake_filling::Entity).into(),
.from(Column::Id)
.to(super::cake_filling::Column::FillingId)
.into(),
} }
} }
} }

View File

@ -55,7 +55,7 @@ impl ColumnTrait for Column {
impl RelationTrait for Relation { impl RelationTrait for Relation {
fn def(&self) -> RelationDef { fn def(&self) -> RelationDef {
match self { match self {
Self::Cake => Entity::has_one(super::cake::Entity) Self::Cake => Entity::belongs_to(super::cake::Entity)
.from(Column::CakeId) .from(Column::CakeId)
.to(super::cake::Column::Id) .to(super::cake::Column::Id)
.into(), .into(),

View File

@ -86,6 +86,10 @@ impl Entity {
.collect() .collect()
} }
pub fn get_relation_defs(&self) -> Vec<TokenStream> {
self.relations.iter().map(|rel| rel.get_def()).collect()
}
pub fn get_relation_rel_types(&self) -> Vec<Ident> { pub fn get_relation_rel_types(&self) -> Vec<Ident> {
self.relations self.relations
.iter() .iter()

View File

@ -1,9 +1,15 @@
use heck::{CamelCase, SnakeCase}; use heck::{CamelCase, SnakeCase};
use proc_macro2::Ident; use proc_macro2::{Ident, TokenStream};
use quote::format_ident; use quote::{format_ident, quote};
use sea_orm::RelationType;
use sea_query::TableForeignKey; use sea_query::TableForeignKey;
#[derive(Clone, Debug)]
pub enum RelationType {
HasOne,
HasMany,
BelongsTo,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Relation { pub struct Relation {
pub(crate) ref_table: String, pub(crate) ref_table: String,
@ -21,10 +27,33 @@ impl Relation {
format_ident!("{}", self.ref_table.to_camel_case()) format_ident!("{}", self.ref_table.to_camel_case())
} }
pub fn get_def(&self) -> TokenStream {
let rel_type = self.get_rel_type();
let ref_table_snake_case = self.get_ref_table_snake_case();
match self.rel_type {
RelationType::HasOne | RelationType::HasMany => {
quote! {
Entity::#rel_type(super::#ref_table_snake_case::Entity).into()
}
}
RelationType::BelongsTo => {
let column_camel_case = self.get_column_camel_case();
let ref_column_camel_case = self.get_ref_column_camel_case();
quote! {
Entity::#rel_type(super::#ref_table_snake_case::Entity)
.from(Column::#column_camel_case)
.to(super::#ref_table_snake_case::Column::#ref_column_camel_case)
.into()
}
}
}
}
pub fn get_rel_type(&self) -> Ident { pub fn get_rel_type(&self) -> Ident {
match self.rel_type { match self.rel_type {
RelationType::HasOne => format_ident!("has_one"), RelationType::HasOne => format_ident!("has_one"),
RelationType::HasMany => format_ident!("has_many"), RelationType::HasMany => format_ident!("has_many"),
RelationType::BelongsTo => format_ident!("belongs_to"),
} }
} }
@ -49,7 +78,7 @@ impl From<&TableForeignKey> for Relation {
}; };
let columns = tbl_fk.get_columns(); let columns = tbl_fk.get_columns();
let ref_columns = tbl_fk.get_ref_columns(); let ref_columns = tbl_fk.get_ref_columns();
let rel_type = RelationType::HasOne; let rel_type = RelationType::BelongsTo;
Self { Self {
ref_table, ref_table,
columns, columns,

View File

@ -1,5 +1,4 @@
use crate::{Entity, EntityWriter, Error, PrimaryKey, Relation}; use crate::{Column, Entity, EntityWriter, Error, PrimaryKey, Relation, RelationType};
use sea_orm::RelationType;
use sea_query::TableStatement; use sea_query::TableStatement;
use sea_schema::mysql::def::Schema; use sea_schema::mysql::def::Schema;
use std::{collections::HashMap, mem::swap}; use std::{collections::HashMap, mem::swap};
@ -31,11 +30,16 @@ impl EntityTransformer {
)) ))
} }
}; };
let columns = table_create let columns: Vec<Column> = table_create
.get_columns() .get_columns()
.iter() .iter()
.map(|col_def| col_def.into()) .map(|col_def| col_def.into())
.collect(); .collect();
let unique_columns: Vec<String> = columns
.iter()
.filter(|col| col.unique)
.map(|col| col.name.clone())
.collect();
let relations = table_create let relations = table_create
.get_foreign_key_create_stmts() .get_foreign_key_create_stmts()
.iter() .iter()
@ -64,9 +68,22 @@ impl EntityTransformer {
entities.push(entity); entities.push(entity);
for mut rel in relations.into_iter() { for mut rel in relations.into_iter() {
let ref_table = rel.ref_table; let ref_table = rel.ref_table;
swap(&mut rel.columns, &mut rel.ref_columns); let mut unique = true;
rel.rel_type = RelationType::HasMany; for col in rel.columns.iter() {
if !unique_columns.contains(col) {
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.ref_table = table_name.clone();
rel.columns = Vec::new();
rel.ref_columns = Vec::new();
if let Some(vec) = inverse_relations.get_mut(&ref_table) { if let Some(vec) = inverse_relations.get_mut(&ref_table) {
vec.push(rel); vec.push(rel);
} else { } else {

View File

@ -217,20 +217,14 @@ impl EntityWriter {
pub fn gen_impl_relation_trait(entity: &Entity) -> TokenStream { pub fn gen_impl_relation_trait(entity: &Entity) -> TokenStream {
let relation_ref_tables_camel_case = entity.get_relation_ref_tables_camel_case(); let relation_ref_tables_camel_case = entity.get_relation_ref_tables_camel_case();
let relation_rel_types = entity.get_relation_rel_types(); let relation_defs = entity.get_relation_defs();
let relation_ref_tables_snake_case = entity.get_relation_ref_tables_snake_case();
let relation_columns_camel_case = entity.get_relation_columns_camel_case();
let relation_ref_columns_camel_case = entity.get_relation_ref_columns_camel_case();
let quoted = if relation_ref_tables_camel_case.is_empty() { let quoted = if relation_ref_tables_camel_case.is_empty() {
quote! { quote! {
_ => panic!("No RelationDef"), _ => panic!("No RelationDef"),
} }
} else { } else {
quote! { quote! {
#(Self::#relation_ref_tables_camel_case => Entity::#relation_rel_types(super::#relation_ref_tables_snake_case::Entity) #(Self::#relation_ref_tables_camel_case => #relation_defs),*
.from(Column::#relation_columns_camel_case)
.to(super::#relation_ref_tables_snake_case::Column::#relation_ref_columns_camel_case)
.into()),*
} }
}; };
quote! { quote! {